核心解法是将innodb_autoinc_lock_mode设为2且binlog_format必须为ROW,否则主从不一致;mode=2用预分配段提升并发但ID不连续,需确认业务不依赖ID连续性并拆分大插入语句。

核心解法是把 innodb_autoinc_lock_mode 从默认的 1 改为 2,但必须同步满足 binlog_format = ROW,否则会引发主从不一致。这不是简单调参,而是对锁行为逻辑的切换。
先确认是不是自增锁在卡住你
别一上来就改参数。先看现象是否匹配:
- show processlist 里大量线程状态是 Waiting for table level lock
- 慢日志中 INSERT 语句耗时突增(尤其 INSERT SELECT、REPLACE SELECT、LOAD DATA)
- QPS 上不去,但 CPU 和磁盘 IO 并不高
- 执行 SHOW ENGINE INNODB STATUS,在 TRANSACTIONS 部分看到 AUTO_INC 锁等待
三种模式的真实影响
不是“0 保守、2 激进”,而是每种对应不同插入类型的锁策略:
- mode = 0:所有 INSERT 类语句(含单行)都加语句级 AUTO_INC 表锁,ID 绝对连续,但并发最差,已基本淘汰
- mode = 1(默认):Simple insert(如 INSERT INTO t VALUES ())只在 ID 分配瞬间加轻量互斥锁;但 INSERT SELECT、REPLACE SELECT 等批量语句仍全程持表锁——这才是高并发下真正的瓶颈点
- mode = 2:所有插入都不加 AUTO_INC 表锁,改用预分配段(如一次拿 100 个 ID),性能最高;但事务回滚后 ID 不回收,必然出现空洞
安全启用 mode = 2 的硬性前提
跳过任一检查,上线即风险:
- 执行 SELECT @@binlog_format,结果必须是 ROW;如果不是,需在配置文件中设置 binlog_format = ROW 并重启 MySQL
- 确认业务不依赖 ID 连续性:比如不用 ID 做分页推算、不对外暴露 ID 当单号、没有代码硬写 “ID + 1 就是下一条”
- 避免混用 INSERT ON DUPLICATE KEY UPDATE + 显式指定自增字段的写法,mode = 2 下可能触发重试开销
配套优化才能真正释放并发
单改参数只是起点,还需调整写入方式:
- 把大 INSERT SELECT 拆成应用层分页 + 批量多值 INSERT,例如每批 500–1000 行:INSERT INTO t VALUES (),(),…()
- 用 INSERT ON DUPLICATE KEY UPDATE 替代 REPLACE,前者只在真正插入新行时才推进自增计数器
- 确保主键字段类型足够大(如 BIGINT UNSIGNED),避免空洞加速耗尽 ID 范围
- 监控空洞程度:对比 SELECT MAX(id) FROM t 和 SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES



















