何时INSERT ... ON DUPLICATE失败?

时间:2015-05-07 18:56:24

标签: mysql constraints unique-constraint

由于约束错误,我正在对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' 

此表上有两个唯一的键。

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`)

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

4 个答案:

答案 0 :(得分:3)

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

例如,假设您的表已经包含以下行:

(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的行),因此ON DUPLICATE KEY UPDATE子句将导致冲突的行被更新代替。但这会导致它违反第二个约束,因为表格中已经另一个id_path = 'category/494'is_system = 1和{{1} }。

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

事实上,what really happens就是如果store_id = 6语句INSERT违反多个唯一性限制,MySQL会尝试将更新应用于所有冲突的行。对于这样的更新,将所有列设置为固定值,这几乎是保证导致进一步的约束违规,因为它有效地尝试使表中的两个不同的行相同。

如链接文档所述:

  

通常,您应该尽量避免在具有多个唯一索引的表上使用ON DUPLICATE KEY UPDATE子句。

答案 1 :(得分:2)

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

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_path id_system 列(在该行上)设置为值 {{1} 'category/494'

那是"重复的键" '1'操作返回了错误。该语句仅捕获由UPDATE操作引起的重复键错误。

错误消息的这一部分:

INSERT

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

在错误消息中,破折号字符用作每列值之间的分隔符。一般来说,我们无法区分作为分隔符的短划线和作为值的一部分的短划线;所以我们需要注意解析它。

在这种情况下,索引中有两个短划线字符和三列,因此我们可以选择为每个列分配的值。

如果'category/494-1-6' 抛出了"重复的密钥"错误,我们不会看到它。 MySQL会抓住它,并调用INSERT动作。导致错误的是UPDATE操作。

答案 2 :(得分:0)

可能你刚刚解决了你的问题,但是我已经把这个提示留给了像我这样来谷歌的其他人。

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

时,也会产生此错误

如果您不使用自定义重写,最快的解决方案就是截断此表并重新重新索引。

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

看起来像INSERT ... ON DUPLICATE UPDATE(由Magento核心索引器使用)每次运行索引器时都会碰坏这个索引。

答案 3 :(得分:0)

请注意,因为A.Maksymiuk建议达到最大unsigned int大小也是一个原因。

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

错误报告“重复条目”与以下MySql错误有关:

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

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

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