MySQL 5.7及更早InnoDB重启后AUTO_INCREMENT变小,因计数器仅存内存,重启执行SELECT MAX(id)+1重建;即使曾插入200又删除,现存最大id为10时新值即为11,且ALTER TABLE设值若未超MAX(id)则重启失效。

MySQL重启后InnoDB的AUTO_INCREMENT为什么变小了
因为InnoDB(5.7及更早)把自增值存在内存里,重启时会执行SELECT MAX(id) + 1 FROM t FOR UPDATE重新推算。如果表中现存最大id是10,哪怕之前插入过200又删掉,重启后AUTO_INCREMENT就变成11,而不是201。
这个值在SHOW CREATE TABLE里能看到,但只是当前内存快照——它不落盘,重启即丢。哪怕你刚执行过ALTER TABLE t AUTO_INCREMENT = 500,只要500没超过当时MAX(id),重启后照样被覆盖。
- MyISAM不受影响:它的最大ID写在.MYI文件头,重启读取即用
- InnoDB 8.0+默认持久化:值写入数据字典,
SHOW CREATE TABLE输出的AUTO_INCREMENT=xxx就是重启后真实值 - 但MyISAM表、或InnoDB启用了
innodb_redo_log_encrypt等异常配置时,仍可能退回到老行为
MyISAM更新某行ID会导致AUTO_INCREMENT跳变
MyISAM对AUTO_INCREMENT的维护是“见最大就记”,且实时同步到文件。比如你有一行id=1,执行UPDATE myisam_test SET id = 105 WHERE id = 1,SHOW CREATE TABLE立刻显示AUTO_INCREMENT=106。
而InnoDB完全不认这种UPDATE——它只看插入时分配过的最大值,以及事务提交后实际存在的最大id。上面那个UPDATE在InnoDB里不会触发AUTO_INCREMENT变更,也不会报错,但后续插入仍按原逻辑走。
- 隐患:跨引擎迁移时,如果业务代码依赖
SHOW CREATE TABLE里的AUTO_INCREMENT值做预判,MyISAM转InnoDB后逻辑会断 - 更隐蔽的是:主从复制中若主库MyISAM、从库InnoDB,
AUTO_INCREMENT不同步,INSERT可能主键冲突
事务回滚和唯一键冲突都会制造不可回收的空洞
InnoDB分配自增值是“预占式”的:事务A申请到id=100,事务B申请到id=101,A回滚了,B提交了,下一个插入就是id=102——100永远空缺。这不是bug,是ACID代价。
MyISAM没有事务,所以不会因回滚丢ID;但它有另一类空洞:崩溃时正在写入INSERT SELECT,中断后文件头记录的最大ID比实际数据少,重启后靠MAX(id)重建,漏掉一批。
-
INSERT IGNORE或ON DUPLICATE KEY UPDATE也会触发自增分配,哪怕最终没插入新行 - 监控发现ID“跳号”严重,别急着查配置,先看业务里有没有高频回滚或唯一键冲突场景
- MyISAM的空洞更难定位,因为它不报错,
CHECK TABLE常返回OK,但查询结果已错乱
ALTER TABLE AUTO_INCREMENT = N容易踩的坑
这个语句不是“设完就生效”,它只在满足条件时才真正修改:N必须严格大于当前表中最大id值。否则:
- MySQL 5.7+:直接报错
ERROR 1062 (23000): Duplicate entry 'X' for key 'PRIMARY' - MySQL 5.6及更早:静默忽略,
SHOW CREATE TABLE里值不变 - 即使设成功了,在InnoDB 5.7及更早版本下,重启后仍会被
MAX(id)+1覆盖
最容易被忽略的一点:OPTIMIZE TABLE在InnoDB上也会触发MAX(id)+1重建逻辑,效果等同于一次“软重启”。如果你在凌晨跑OPTIMIZE,白天业务突然发现ID从1000跳回1001,大概率就是它干的。


















