【问题标题】:mysql duplicate entry error when there is no duplicate entry (bulk load via php)没有重复条目时的mysql重复条目错误(通过php批量加载)
【发布时间】:2010-09-18 07:05:43
【问题描述】:

我正在使用 mysql (5.0.32-Debian_7etch6-log) 并且我有一个夜间运行的批量加载 php (5.2.6) 脚本 (通过 PDO 使用 Zend_DB (1.5.1))执行以下操作:

  1. 截断一组 4 个“导入”表
  2. 将数据批量插入到这 4 个“导入”表中(重新使用以前在表中的 id,但我截断了整个表,所以这应该不是问题,对吧?)
  3. 如果一切顺利,将“live”表重命名为“temp”,将“import”表重命名为“live”,然后将“temp”(旧的“live”)表重命名为“import”

这几个星期都很好用。现在我偶尔会得到这个,在整个批量加载过程的中间的某个地方:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '911' for key 1

请注意,这不是截断之前表中的第一个 id。当我再次手动启动脚本时,它就像一个魅力。

有什么想法吗?剩余索引,可能与重命名有关?

此外,当我之后检查表中 id 为 911 的条目时,它甚至都不在那里。

【问题讨论】:

    标签: php mysql rename truncate mysql-error-1062


    【解决方案1】:

    在您的导入脚本运行时,是否有其他脚本正在插入到数据库中?

    【讨论】:

      【解决方案2】:

      您是否尝试过启用查询日志以查看您是否真的在插入重复项?

      你能在你的测试环境中重现它吗?不要在生产环境中启用查询日志。

      如果问题是真实的,则表可能已损坏;这可能是由多种原因造成的,但也有可能是硬件故障或电源故障。

      查看mysql日志,看看最近或期间是否有任何问题(或崩溃)。

      同样,我能建议的只是尝试在您的测试环境中重现它。创建大量测试数据并重复加载它们。

      【讨论】:

        【解决方案3】:

        显然存在一些锁定问题或其他问题,我能够通过在并行连接中将“SELECT”语句发送到受影响的和相关的表来重现该行为。

        现在我使用 DELETE FROM 而不是 TRUNCATE 并将 RENAME TABLE 语句(我一次做了 3 次重命名)更改为一堆单个 ALTER TABLE xxx RENAME TO zzz 语句,并且无法再重现错误。

        所以这可能会解决。也许其他人可以从我花在研究和大量尝试和错误上的一天中受益。

        【讨论】:

          【解决方案4】:

          您正在使用交易吗?您可以消除事务中的许多此类问题,尤其是在可以锁定表或将事务隔离模式设置为可序列化的情况下。我不太熟悉 MySQL 上的那些,但我相信事务只适用于 InnoDB 表(或者这可能是过时的知识)。

          【讨论】:

            【解决方案5】:

            当 MyISAM 表损坏时,可能会发生此类错误。在有问题的表上运行修复命令通常是修复它所需的全部:

            > repair table mytablename;
            

            更好的解决方案是不要将 MyISAM 用于数据不断变化的表 - InnoDB 更加防弹,正如 Paul 正确指出的那样,您可以在 InnoDB 表上使用事务,但不能在 MyISAM 上使用。

            顺便说一句,我会避免在运行中重命名表 - 定期这样做是一件相当笨重的事情,如果在重命名过程中系统上有其他用户,可能会导致一些非常意想不到的结果在。为什么不这样做:

            > truncate table temptable;
            > truncate table importtable;
            
            > #bulk insert new data
            > insert into importtable(col1,col2,col3) 
            > values(1,2,3),(4,5,6),(7,8,9);
            
            > #now archive the live data
            > insert into temptable(col1,col2,col3)
            > select col1,col2,col3 from livetable;
            
            > #finally copy the new data to live
            > truncate table livetable;
            > insert into livetable(col1,col2,col3)
            > select col1,col2,col3 from importtable;
            

            当然,如果您要插入大量行,那么风险就是,只要插入需要完成,您的所有实时数据都将不可用,但总体而言,这种方法对索引、触发器的破坏性要小得多或任何其他可能与相关表格相关联的内容。

            【讨论】:

              【解决方案6】:

              您正在创建一条省略了“id”字段(或为 NULL)的新记录, 但是之前您已经更新了另一条记录并将其“id”更改为“911”。 换句话说,如果您的表的 AUTO_INCREMENT 值被采用,您将无法创建另一条记录。

              【讨论】:

                猜你喜欢
                • 2012-10-19
                • 2019-11-26
                • 1970-01-01
                • 2012-02-04
                • 1970-01-01
                • 1970-01-01
                • 2019-02-23
                • 2011-09-13
                • 1970-01-01
                相关资源
                最近更新 更多