【问题标题】:When Would This INSERT.. ON DUPLICATE Fail?这个 INSERT.. ON DUPLICATE 什么时候会失败?
【发布时间】:2015-05-07 18:56:23
【问题描述】:

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

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

【问题讨论】:

    标签: mysql constraints unique-constraint


    【解决方案1】:

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

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

    (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 子句将导致冲突行被更新。但这会导致它违反 second 约束,因为表中已经有 another 行带有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 将尝试将更新应用于所有冲突的行。对于这样的更新,将所有列设置为固定值,几乎保证会导致进一步的约束违规,因为它实际上是在尝试使表中的两个不同行相同。

    作为链接的文档说明:

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

    【讨论】:

    • 我认为这正是发生的。另一个唯一约束失败,但错误出现在您列出的第二个约束上!似乎没有针对这个特定问题的简单而优雅的解决方案,因为我认为在达到这一点之前存在一些完整性问题,因为我需要对UNQ_CORE_URL_REWRITE_REQUEST_PATH_STORE_ID 中的request_path 以及新的我要插入的记录。
    【解决方案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_pathid_system 列(在该行)设置为值 'category/494''1'

    UPDATE 操作返回了“重复键”错误。该语句仅捕获由INSERT 操作引起的重复键错误。


    这部分错误信息:

    'category/494-1-6'
    

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

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

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


    如果INSERT 抛出了“重复键”错误,我们就不会看到它。 MySQL 会捕捉到这一点,并调用UPDATE 操作。是 UPDATE 操作导致了错误。

    【讨论】:

      【解决方案3】:

      可能您刚刚解决了您的问题,但我将这里的提示留给像我一样从谷歌来到这里的其他人。

      url_rewrite_id 达到 ma​​x unsigned int size 4,294,967,295

      时也会产生此错误

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

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

      似乎 INSERT ... ON DUPLICATE UPDATE(由 Magento 核心索引器使用)每次运行索引器时都会碰撞此索引。

      【讨论】:

        【解决方案4】:

        注意 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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-06-03
          • 1970-01-01
          • 1970-01-01
          • 2016-11-30
          • 1970-01-01
          • 2015-09-24
          • 2022-01-05
          • 2010-10-07
          相关资源
          最近更新 更多