innodb_autoinc_lock_mode=2 可直接开启,但仅对Simple inserts无锁,Bulk/Mixed插入仍需锁,且binlog必须为ROW格式;预分配ID会导致主键空洞,不可回填。

innodb_autoinc_lock_mode=2 能否直接开?要看写入类型
能开,但不是所有场景都安全。这个参数控制的是自增 ID 分配时的加锁策略,直接影响 INSERT 并发能力。关键在于区分你用的是哪种插入语句:Simple inserts(如 INSERT INTO t VALUES ())、Bulk inserts(如 INSERT ... SELECT)还是 Mixed-mode inserts(部分行显式指定 AUTO_INCREMENT 值)。只有 Simple inserts 在 mode=2 下才完全无表级锁;Bulk inserts 仍会退化为语句级锁,mode=2 对它没提升。
常见错误现象是:开了 mode=2,但大量 INSERT ... SELECT 或 REPLACE INTO ... SELECT 还是卡住——这不是配置没生效,而是语句类型本身不走轻量路径。
- mode=0(传统模式):所有插入都加
AUTO-INC表级锁,最安全但并发最差 - mode=1(连续模式,默认):
Simple inserts只在分配 ID 阶段加锁,之后立刻释放;Bulk inserts仍全程持锁 - mode=2(交错模式):仅对
Simple inserts完全无锁;Bulk inserts和混合插入仍需锁,且 binlog 格式必须为ROW,否则主从不一致
为什么 mode=2 可能导致主键空洞?这和事务回滚有关
mode=2 下,InnoDB 采用“预分配 + 异步提交”策略:事务开始时就批量预取一段 ID(比如一次拿 100 个),即使后续事务回滚,这些 ID 也不会回收。所以你会看到 AUTO_INCREMENT 值跳变,比如刚插完 1001,下一条却是 1057。
这不是 bug,是设计取舍。空洞本身不影响功能,但如果你依赖 ID 的“严格连续性”做业务逻辑(比如分页推算、ID 范围校验),就会出问题。更隐蔽的风险是:当应用层重试失败插入(比如唯一键冲突后换 ID 重试),叠加 mode=2 的预分配,空洞会加速扩大。
- 空洞只影响主键值序列,不影响索引结构或查询性能
-
SHOW TABLE STATUS返回的Auto_increment值反映的是“下一个预分配起点”,不是当前最大值 - 无法通过
ALTER TABLE ... AUTO_INCREMENT = N回填空洞,该语句只设置下限
mode=2 配合哪些操作才能真正提升并发?
单改 innodb_autoinc_lock_mode 不够,必须同步调整写入方式。高并发插入的瓶颈常不在 ID 分配本身,而在日志刷盘、事务开销和索引维护上。
实操建议优先做这三件事:
- 把单条
INSERT INTO t VALUES (1),(2)改成批量插入,每批控制在 500~2000 行,避免每行都触发一次 ID 分配逻辑 - 关闭唯一性检查:
SET UNIQUE_CHECKS=0,再执行大批量导入;完成后记得SET UNIQUE_CHECKS=1并ANALYZE TABLE t - 调低日志刷盘强度:
innodb_flush_log_at_trx_commit = 2(崩溃最多丢 1 秒数据),配合sync_binlog = 0可进一步提速,但需评估一致性要求
注意:LOAD DATA INFILE 在 mode=2 下依然走 Bulk inserts 路径,不会受益于无锁分配,但它本身已足够快,不必强求 mode 匹配。
MyISAM 能绕过这个问题吗?别被表级锁骗了
MyISAM 确实用表级锁,但它的 AUTO_INCREMENT 锁是语句级且不阻塞读,看起来比 InnoDB “轻”。可实际高并发写入时,MyISAM 的数据文件尾部追加虽快,一旦有 DELETE 或更新产生空闲块(free blocks),后续插入可能触发碎片整理,反而更慢。更重要的是:MyISAM 不支持事务、崩溃恢复弱、无行级并发,现代业务基本不用。
真正要规避 InnoDB 自增热点,不是换引擎,而是拆解压力:
- 用
UNSIGNED BIGINT主键,避免因类型溢出被迫重建表 - 高频写入表考虑按时间/业务维度分表(如
t_202604),分散AUTO_INCREMENT热点 - 对日志类数据,先写 Kafka/Redis,消费者聚合后再批量落库,彻底绕过实时自增分配
最易被忽略的一点:很多“高并发插入慢”的问题,根源不在自增锁,而在二级索引太多——每多一个索引,每次插入就要多维护一棵 B+ 树。删掉非必要索引,比调 innodb_autoinc_lock_mode 更立竿见影。



















