开了innodb_autoinc_lock_mode=2仍排队,是因为该模式仅对INSERT INTO t VALUES()类简单插入无锁,而含SELECT、REPLACE、LOAD DATA或混合显式ID的语句仍强制使用语句级AUTO-INC表锁。

为什么开了 innodb_autoinc_lock_mode = 2 还在排队?
不是参数没生效,是你写的 INSERT 语句根本没走轻量路径。MySQL 的 mode=2 只对 INSERT INTO t VALUES () 这类 simple insert 跳过 AUTO-INC 锁;一旦语句里带 SELECT、REPLACE、LOAD DATA 或混用显式 ID(如 (100,'a'), (NULL,'b')),InnoDB 就强制退化为语句级表锁——执行多久,锁就 hold 多久。
常见卡点现象:
-
SHOW PROCESSLIST里大量线程状态是Waiting for table level lock - 慢日志中
INSERT INTO t SELECT ...耗时突增,但EXPLAIN显示执行计划正常 -
SHOW ENGINE INNODB STATUS的 TRANSACTIONS 段出现AUTO_INC等待
怎么确认你的业务真能开 innodb_autoinc_lock_mode = 2?
跳过这三步检查,上线可能直接导致主从断裂或业务逻辑错乱:
- 执行
SELECT @@binlog_format,结果必须是ROW;STATEMENT或MIXED格式下开启 mode=2 会触发降级警告甚至复制中断 - 确认业务不依赖 ID 连续性:没有代码硬写
id + 1推算下一条、不用 ID 做分页偏移、不对外暴露 ID 当单号 - 检查分库分表中间件或应用层逻辑是否假设 ID 单调递增——某些路由策略会因预分配段跳号而失效
不改配置,怎么绕过自增锁瓶颈?
真正压垮并发的常是写入模式本身,而不是锁机制。优先从 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,否则触发内部重试,反而增加开销 - 大批量导入前临时关闭唯一性检查:
SET UNIQUE_CHECKS=0,导入完再SET UNIQUE_CHECKS=1并ANALYZE TABLE
批量提交 + mode=2 组合使用的实操陷阱
这两项合起来才出真性能,但极易踩坑:
- 主键乱序插入(如按时间倒序)会导致二级索引频繁分裂,吞掉一半提速收益;务必保证
VALUES中的主键值单调递增 - 没关非主键索引时,每插一条仍要更新所有索引树;建议导入前
DROP INDEX,导入完CREATE INDEX -
innodb_flush_log_at_trx_commit=1(默认)下,即使批量提交,每次COMMIT仍强制刷盘;临时改成0可再提速 30%,但断电会丢最近 1 秒事务 - ORM(如 MyBatis、Hibernate)可能自动拆分批量语句或强制每条都 flush,得关掉批量代理逻辑,直连 JDBC 执行原生 SQL
最容易被忽略的是:mode=2 下的 ID 分配不可预测,应用层若做了“插入后立刻用刚生成的 ID 做关联查询”并假设它紧邻前一个 ID,这种逻辑会失效。


















