最有效手段是设innodb_autoinc_lock_mode=2且binlog_format=ROW;mode=1对含SELECT/REPLACE/LOAD DATA的语句仍用语句级AUTO_INC锁,导致高并发下排队阻塞,而mode=2仅对简单INSERT跳过锁,Bulk/Mixed插入仍需表锁。

直接设 innodb_autoinc_lock_mode = 2 是最有效手段,但必须同时满足 binlog_format = ROW,否则不仅无效,还可能中断主从复制。
为什么默认 mode=1 在高并发插入时会卡住
MySQL 8.0 默认 innodb_autoinc_lock_mode = 1,它对 INSERT INTO t VALUES () 这类简单插入用轻量互斥锁,很快释放;但只要语句里带 SELECT(如 INSERT INTO t SELECT * FROM s)、REPLACE INTO 或 LOAD DATA,InnoDB 就会升级为语句级 AUTO_INC 表锁——锁持有到整条语句执行完。这意味着:
- 一条
INSERT INTO t SELECT ... LIMIT 10000正在跑,其他所有INSERT都得排队 -
SHOW PROCESSLIST里大量出现Waiting for table level lock或waiting for auto-inc lock on t - 即使 QPS 很低,单条插入耗时也可能从几毫秒跳到几百毫秒甚至秒级
mode=2 的真实行为和硬性前提
innodb_autoinc_lock_mode = 2 不是“完全无锁”,而是用原子递增的全局计数器替代表级锁,但它有明确边界:
- 仅对
Simple inserts(如INSERT INTO t VALUES ())真正跳过锁;Bulk inserts(含SELECT)和Mixed-mode inserts(部分行显式指定自增值)仍退化为语句级锁 -
binlog_format必须为ROW:执行SELECT @@binlog_format确认返回ROW,否则 MySQL 启动会警告或降级,主从可能丢数据 - ID 必然不连续:事务回滚、批量插入部分失败、预分配段(如一次拿 100 个 ID)都会导致空洞,比如刚插完 1001,下一条可能是 1057
- 不兼容 MyISAM:该模式只对 InnoDB 生效,且 MySQL 8.0 已移除 MyISAM 引擎支持
怎么验证 mode=2 是否真正生效
改完配置不等于问题消失,得看运行时表现:
- 执行
SHOW VARIABLES LIKE 'innodb_autoinc_lock_mode'确认值为2 - 执行
SHOW VARIABLES LIKE 'binlog_format'确认值为ROW - 压测并发插入时,用
SHOW ENGINE INNODB STATUS检查输出,确认不再出现AUTO-INC相关等待线程 - 查
information_schema.INNODB_METRICS中的autoinc_wait_count,数值应持续接近0 -
SHOW TABLE STATUS显示的Auto_increment值跳变是正常现象,不代表配置失败
最容易被忽略的是:mode=2 下 ID 分配不可预测。如果你的应用层假设“刚插入的 ID 紧邻前一个”来做关联查询,或分库分表中间件依赖 ID 单调递增做路由,切换前必须实测兼容性——这不是参数能绕过的逻辑耦合。


















