innodb_autoinc_lock_mode=2仅对simple insert(如INSERT INTO t VALUES())生效,对INSERT SELECT、REPLACE SELECT等bulk/mixed插入仍需语句级锁,故调参无效;应优先优化SQL写法,如分页批量插入、避免混用显隐ID,并确认binlog_format=ROW且业务不依赖ID连续性。

直接改 innodb_autoinc_lock_mode = 2 能缓解,但仅对 INSERT INTO t VALUES () 类简单插入生效;如果你的业务里大量跑 INSERT INTO t SELECT ... 或 REPLACE INTO t SELECT ...,调这个参数根本没用——卡点不在参数,而在语句本身。
怎么确认真是 AUTO-INC 锁在卡住你
别一上来就改配置。先看现象是否匹配:
-
SHOW PROCESSLIST里大量线程状态是Waiting for table level lock - 慢日志里
INSERT耗时突增(尤其带SELECT、REPLACE、LOAD DATA的语句),但EXPLAIN显示执行计划正常 - QPS 上不去,CPU 却被
innodb_autoinc_lock相关函数吃满 -
SHOW ENGINE INNODB STATUS的TRANSACTIONS部分出现AUTO_INC锁等待
为什么 innodb_autoinc_lock_mode = 2 开了还是卡
因为 mode=2 只跳过 Simple inserts 的锁,其他两类仍要锁:
-
Bulk inserts(如INSERT INTO t SELECT ...、LOAD DATA INFILE):mode=2 下依然退化为语句级锁,执行多久锁多久 -
Mixed-mode inserts(如INSERT INTO t VALUES (100,'x'), (NULL,'y')):显式 + 隐式混用,也会触发锁 - 即使开了 mode=2,只要语句里含
SELECT,InnoDB 就不走轻量路径
所以看到 INSERT SELECT 还在排队,不是参数没生效,是你写法本身就不适配 mode=2。
不靠参数,怎么绕过锁瓶颈
真正压垮并发的常是写入模式,不是锁机制本身。优先从 SQL 写法入手:
- 把
INSERT INTO t SELECT ... FROM s WHERE ...拆成应用层分页 + 批量多值插入,每批控制在 500–1000 行:INSERT INTO t VALUES (),(),...() - 用
INSERT ON DUPLICATE KEY UPDATE替代REPLACE INTO:前者只在真正插入新行时才推进自增计数器,更省 ID、更少锁 - 避免在 mode=2 下混用显式 ID 和
NULL,比如INSERT INTO t VALUES (100,'a'), (NULL,'b'),会触发内部重试开销 - 大批量导入时,临时关闭唯一性检查:
SET UNIQUE_CHECKS=0,导入完再SET UNIQUE_CHECKS=1并ANALYZE TABLE
改参数前必须验的三件事
跳过任一检查,上线即风险:
- 执行
SELECT @@binlog_format,结果必须是ROW;否则主从复制可能丢数据或中断 - 确认业务不依赖 ID 连续性:比如不用 ID 做分页推算、不对外暴露 ID 当单号、没有代码硬写
id + 1就是下一条 -
SET GLOBAL innodb_autoinc_lock_mode = 2立即生效但重启失效,必须写进my.cnf的[mysqld]段才持久
mode=2 下的 ID 空洞不是 bug,是设计行为——事务回滚后预分配的 ID 不回收。只要业务不拿 ID 做逻辑推算,空洞就只是数字跳变,不影响功能。


















