这个 INSERT.. ON DUPLICATE 什么时候会失败?

When Would This INSERT.. ON DUPLICATE Fail?

由于约束错误,我正在对 INSERT... ON DUPLICATE KEY 语句进行故障排除,但我不可逆转地编辑了有问题的行,并且我不再收到错误。我很确定我编辑了 request_pathtarget_path。某些区域已经存在的一些值:

store_id |   id_path    | is_system
   6     | category/494 |     1

查询是

INSERT INTO `core_url_rewrite` (`store_id`,`category_id`,`product_id`,`id_path`,`request_path`,`target_path`,`is_system`) 
VALUES (6, 494, NULL, 'category/494', 'lessons/teacher-s-planning-calendar/n-a', 'catalog/category/view/id/494', 1) 
ON DUPLICATE KEY UPDATE 
    `store_id` = VALUES(`store_id`),
    `category_id` = VALUES(`category_id`), 
    `product_id` = VALUES(`product_id`), 
    `id_path` = VALUES(`id_path`), 
    `request_path` = VALUES(`request_path`), 
    `target_path` = VALUES(`target_path`), 
    `is_system` = VALUES(`is_system`)

错误是

Integrity constraint violation: 1062 Duplicate entry 'category/494-1-6' 
for key 'UNQ_CORE_URL_REWRITE_ID_PATH_IS_SYSTEM_STORE_ID' 

这个 table 上有两个唯一键。

UNIQUE KEY `UNQ_CORE_URL_REWRITE_REQUEST_PATH_STORE_ID` (`request_path`,`store_id`),
UNIQUE KEY `UNQ_CORE_URL_REWRITE_ID_PATH_IS_SYSTEM_STORE_ID` (`id_path`,`is_system`,`store_id`)

在手动意外更改行上的某些值后,我不再收到此约束错误。什么会导致我的查询提示约束错误?

如果修复第一个唯一性约束(通过更新冲突行而不是插入新行)导致第二个失败,则会发生这种情况。

例如,假设您的 table 已经有以下行:

(6, 494, NULL, 'category/123', 'lessons/teacher-s-planning-calendar/n-a', 'catalog/category/view/id/123', 1),
(6, 494, NULL, 'category/494', 'lessons/foobar/whatever', 'catalog/category/view/id/494', 1);

然后尝试插入新行:

(6, 494, NULL, 'category/494', 'lessons/teacher-s-planning-calendar/n-a', 'catalog/category/view/id/494', 1)

将导致第一个约束失败(因为 request_path = 'lessons/teacher-s-planning-calendar/n-a'store_id = 6 的行已经存在于 table 中),因此 ON DUPLICATE KEY UPDATE 子句将导致而是更新冲突的行。但这将导致它违反 second 约束,因为在 table 中已经有 另一个 id_path = 'category/494'is_system = 1store_id = 6.

Here's a simple example on SQLize demonstrating this behavior.


事实上,what really happens是,如果ON DUPLICATE KEY UPDATEINSERT语句违反了多个唯一性约束,MySQL将尝试将更新应用到所有 冲突的行。对于这样的更新,将所有列设置为固定值,这几乎 保证 会导致进一步的约束违规,因为它实际上是在尝试在 [=48= 中创建两个不同的行] 相同。

如链接文档所述:

In general, you should try to avoid using an ON DUPLICATE KEY UPDATE clause on tables with multiple unique indexes.

问:什么会导致我的查询提示约束错误?

INSERT 操作在第一个唯一键 (request_path,store_id) 上遇到重复键错误。该错误被 MySQL 捕获,然后 MySQL 执行了等同于

的操作
UPDATE core_url_rewrite
   SET store_id     = ?
     , category_id  = ?
     , product_id   = ?
     , id_path      = ?
     , request_path = ?
     , target_path  = ?
     , is_system    = ?
 WHERE ( request_path = ? AND store_id = ? )
    OR ( id_path = ? AND id_system = ? AND store_id = ?)
 LIMIT 1

更新操作试图将 id_pathid_system 列(在该行)设置为值 'category/494''1'

"duplicate key" 错误是从 UPDATE 操作返回的。该语句仅捕获由 INSERT 操作引起的重复键错误。


这部分错误信息:

'category/494-1-6'

表示构成 table 中已存在的唯一键的列中的值。

在错误消息中,破折号用作每列值之间的分隔符。通常,我们无法区分作为分隔符的破折号和作为值一部分的破折号;所以我们需要小心解析它。

在本例中,索引中有两个破折号和三列,因此我们可以找出分配给每一列的值。


如果 INSERT 抛出了 "duplicate key" 错误,我们就不会看到它。 MySQL 会捕捉到它,并调用 UPDATE 动作。导致错误的是 UPDATE 操作。

可能你刚刚解决了你的问题,但我在这里把提示留给像我一样从 google 来到这里的其他人。

url_rewrite_id达到max unsigned int size 4,294,967,295

时也会产生这个错误

最快的解决方案就是 t运行cate this table,如果您不使用自定义重写,则再次重新编制索引。

$adapter->insertOnDuplicate($this->getMainTable(), $rewriteData);

似乎每次索引器为 运行.

时,INSERT ... ON DUPLICATE UPDATE(由 Magento 核心索引器使用)都会增加此索引

请注意,A.Maksymiuk 建议达到最大无符号整数大小也是一个原因。

在我们的例子中,我们在我们的 ERP 集成中手动插入和删除了很多行,因此 MySql AUTO_INCREMENT 字段的增加速度比实际记录快得多。

错误报告 'Duplicate Entry' 与此 MySql 错误有关:

https://bugs.mysql.com/bug.php?id=80373

https://bugs.mysql.com/bug.php?id=66566

在我们的例子中,我们将列的类型 url_rewrite_id 更改为 BIGINT