我们有一张 MySQL 表,其中有一个设置为 INT (11) 的自动递增字段。该表基本上存储了应用程序中正在运行的作业列表。在应用程序生命周期的任何给定时刻,该表可能包含数千个条目,也可能完全为空(即所有操作都已完成)。
该字段不是任何其他字段的外键。
自动增量似乎会随机重置为零,尽管我们实际上从未能够捕获重置。
问题变得明显,因为我们看到自动增量字段达到了 600,000 条记录左右,而过了一会儿,自动增量字段似乎在 1000 多条记录左右运行。
如果表是空的,自动增量几乎会自行重置。
这可能吗?如果可以,我该如何关闭它或更改其重置方式?
如果不是,有人可以解释为什么它会这样做吗?
谢谢!
答案1
自动增量计数器仅存储在主存储器中,而不存储在磁盘上。
http://dev.mysql.com/doc/refman/4.1/en/innodb-auto-increment-handling.html
因此,当服务(或服务器)重新启动时,会发生以下情况:
服务器启动后,第一次向表 t 插入数据时,InnoDB 会执行与该语句等效的语句:SELECT MAX(ai_col) FROM t FOR UPDATE;
InnoDB 将语句检索到的值加一,并将其分配给列和表的自动递增计数器。如果表为空,InnoDB 将使用值 1。
简而言之,MySQL 服务启动后,它不知道表的自动增量值应该是多少。因此,当您第一次插入一行时,它会找到使用自动增量的字段的最大值,将 1 加到该值,然后使用结果值。如果没有行,它将从 1 开始。
这对我们来说是个问题,因为我们使用表和 mysql 的自动递增功能在多线程环境中巧妙地管理 ID,而用户会被重定向到第三方支付网站。因此,我们必须确保第三方获得并发回给我们的 ID 是唯一的,并且会保持这种状态(当然,用户在被重定向后可能会取消交易)。
因此,我们创建一行,获取生成的自动增量值,删除该行以保持表整洁,并将该值转发到支付网站。我们最终采取以下措施来解决 InnoDB 处理 AI 值的方式问题:
$query = "INSERT INTO transactions_counter () VALUES ();";
mysql_query($query);
$transactionId = mysql_insert_id();
$previousId = $transactionId - 1;
$query = "DELETE FROM transactions_counter WHERE transactionId='$previousId';";
mysql_query($query);
这样始终会将最新生成的交易 ID 作为表中的一行保存,而不会不必要地炸毁表格。
希望这可以帮助其他可能遇到此问题的人。
编辑(2018-04-18):
正如 Finesse 下面提到的那样,这种行为似乎已在 MySQL 8.0+ 中进行了修改。
https://dev.mysql.com/worklog/task/?id=6204
该工作日志中的措辞充其量是有错误的,但是看起来新版本中的 InnoDB 现在支持重启后持久的自动增加值。
—格雷米奥
答案2
我们遇到过这个问题,并且发现当对空表运行优化表时,自动增量值也会被重置。请参阅此 MySQL 错误报告。
作为一种解决方法,您可以执行以下操作:
ALTER TABLE a AUTO_INCREMENT=3 ENGINE=innoDB;
代替OPTIMIZE TABLE
。
看来这就是 MySQL 内部所做的事情(显然没有设置自动增量值)
答案3
答案4
更改表表名 ENGINE=MyISAM
对我来说很管用。我们的表总是保持很小,所以不需要 InnoDB。