innodb_autoinc_lock_mode有三种取值:0(传统模式,全表锁)、1(默认连续模式,simple insert轻量锁、bulk insert表级锁)、2(交错模式,全轻量锁但id不连续且需binlog_format=row)。

直接改 innodb_autoinc_lock_mode 是最有效、最低风险的解法,但必须结合插入语句类型判断——不是所有场景都适合调高模式值。
哪些插入会触发 AUTO-INC 锁
MySQL 对自增列的加锁行为取决于语句类型,而非是否用了事务:
-
INSERT INTO t (name) VALUES ('a'), ('b'):属于 simple insert,行数确定,锁粒度最轻 -
INSERT INTO t (name) SELECT name FROM s WHERE id > 100:属于 bulk insert,行数不确定,会持表级 AUTO-INC 锁直到语句结束 -
INSERT INTO t (id, name) VALUES (1, 'x'), (NULL, 'y'):属于 mixed-mode insert,部分显式指定自增值,InnoDB 仍按 bulk insert 处理 -
INSERT ... ON DUPLICATE KEY UPDATE:虽是 simple insert 语法,但内部执行路径可能退化为 bulk 行为(尤其在有唯一索引冲突时),innodb_autoinc_lock_mode = 0下极易阻塞
三种 lock_mode 的实际表现差异
MySQL 5.7 默认是 innodb_autoinc_lock_mode = 1,但不同模式对并发写入的影响非常具体:
-
innodb_autoinc_lock_mode = 0(traditional):所有 INSERT-like 语句都用表级 AUTO-INC 锁,语句执行完才释放。高并发下几乎串行插入,吞吐量断崖下跌 -
innodb_autoinc_lock_mode = 1(consecutive,默认):simple insert 用轻量互斥量分配 ID,bulk insert 才升为表级锁。适合大多数业务,但 bulk 场景(如定时同步任务)仍会卡住其他插入 -
innodb_autoinc_lock_mode = 2(interleaved):所有插入都用轻量互斥量,ID 不保证连续(主从复制需 binlog_format=ROW)。并发吞吐最高,但如果你依赖自增值做业务排序或分页,可能出问题
调整前必须确认的三件事
盲目设成 2 可能引发隐性故障,务必验证:
- 你的 binlog 格式是不是
ROW?执行SELECT @@binlog_format,如果不是,innodb_autoinc_lock_mode = 2会导致主从自增不一致 - 应用里有没有逻辑依赖自增 ID 的“连续性”?比如用
id BETWEEN 1000 AND 1010做批量拉取,mode=2下跳号会让这类查询漏数据 - 是否存在混合使用
INSERT ... SELECT和单行INSERT的场景?如果 bulk 插入频次低,但 simple 插入并发极高,mode=1已足够,没必要上mode=2
实操步骤与验证点
修改后不能只看配置生效,要观察真实负载下的锁等待和插入延迟:
- 临时生效(重启前验证):
SET GLOBAL innodb_autoinc_lock_mode = 2;注意该变量不可动态降级(0→1或1→2可以,反过来不行) - 永久生效:编辑宝塔面板中实际生效的配置文件(通常是
/www/server/mysql/etc/my.cnf),在[mysqld]下添加innodb_autoinc_lock_mode = 2,然后在面板点“保存”并重启 MySQL - 验证是否生效:
SELECT @@innodb_autoinc_lock_mode;再查SHOW ENGINE INNODB STATUS\G中的SEMAPHORES部分,bulk insert 减少后,os_waits中wait for autoinc mutex次数应明显下降
真正容易被忽略的是 mixed-mode insert —— 它看起来像 simple insert,却悄悄触发 bulk 锁行为。哪怕你把 mode 调到 2,只要语句里混着显式 ID 和 NULL,InnoDB 就可能回退处理逻辑。这种细节不会报错,但会悄悄吃掉并发收益。











