mysql自增id不连续是innodb正常行为,由事务回滚不回收、批量插入预分配、delete不重置计数器、auto_increment_offset/increment配置及主从复制设置等机制共同导致,连续性不在保证范围内。

事务回滚后ID不回收
插入时自增值在语句执行阶段就已分配,而非提交阶段。一旦事务回滚,数据被撤销,但ID不会退还。
常见错误现象:Duplicate entry '100' for key 'PRIMARY' 通常不是因为ID重复,而是误以为回滚能“腾出”ID;实际上ID=100已被占用过,计数器已推进到101。
- 事务A执行
INSERT INTO t VALUES (),拿到ID=100,未提交 - 事务B同样执行该语句,拿到ID=101并提交成功
- 事务A回滚 → ID=100永久空缺,下一条插入从102开始
批量插入预分配ID段
当使用 INSERT INTO t SELECT ...、LOAD DATA INFILE 或多值 INSERT INTO t VALUES (),(),() 时,InnoDB按 innodb_autoinc_lock_mode 策略一次性预申请多个ID,哪怕部分失败也不释放。
性能影响明显:mode=1(默认)下,一次 INSERT SELECT 可能跳号几百甚至上千;mode=2虽并发更高,但ID分配更不可控。
- 查当前模式:
SELECT @@innodb_autoinc_lock_mode; - mode=1 是迁移后ID突增的主因,非bug,是复制安全与性能的折中
- 不能靠重放SQL复现源库ID顺序——导出时的“空洞”不会被保存
DELETE操作不重置计数器
删除某行(如 DELETE FROM t WHERE id = 5)只移除数据,不触碰自增计数器。下一次插入仍基于当前最大ID+1。
容易踩的坑:有人用 DELETE FROM t 清空表后立刻 ALTER TABLE t AUTO_INCREMENT = 1,却发现无效——因为InnoDB会静默忽略小于当前 MAX(id) 的设置。
- 生效前提:必须满足
ALTER TABLE t AUTO_INCREMENT = N中N > (SELECT MAX(id) FROM t) - 真正归零只能用
TRUNCATE TABLE t,但它要求无外键引用且需DROP权限 - 线上表慎用重置:若下游系统缓存了旧ID做分页或幂等校验,可能引发逻辑错乱
auto_increment_offset 和 auto_increment_increment 非默认值
这两个全局变量控制起始值和步长,默认都是1。一旦修改(常见于多主写入或分库分表场景),ID序列立即变为等差数列。
典型配置:SET GLOBAL auto_increment_offset = 2; SET GLOBAL auto_increment_increment = 3; → ID序列为2,5,8,11…
- 主从复制中若主库设offset=1、从库offset=2,又用STATEMENT格式binlog,极易导致主从ID冲突
- 该配置对所有新表生效,已有表不受影响,但新建表会立刻体现
- 查看当前值:
SELECT @@auto_increment_offset, @@auto_increment_increment;











