6

我正在使用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 的条目时,它甚至不在那里。

4

6 回答 6

2

当 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;

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

于 2008-10-22T02:04:51.657 回答
1

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

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

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

于 2008-10-21T18:20:39.787 回答
0

在您的导入脚本运行时,是否可以将其他一些脚本插入到数据库中?

于 2008-10-21T10:41:43.143 回答
0

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

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

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

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

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

于 2008-10-21T10:44:57.473 回答
0

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

于 2009-10-16T16:25:22.797 回答
0

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

于 2008-10-21T20:40:41.563 回答