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

直接结论:优化InnoDB自增主键锁定机制,核心是调高 innodb_autoinc_lock_mode 到 2,并确保 binlog_format=ROW;盲目设为 0 或 1 在高并发写入场景下会成为明显瓶颈。
为什么innodb_autoinc_lock_mode=1(默认)在高并发时仍会卡住?
MySQL 8.0 默认值 innodb_autoinc_lock_mode=1 对简单 INSERT(如 INSERT INTO t(name) VALUES ('a'))用轻量 mutex,但对任何含子查询或批量来源的语句(如 INSERT INTO t SELECT ... FROM src、REPLACE INTO、LOAD DATA)仍会升级为表级 AUTO-INC 锁,且锁持有到整个语句结束。这意味着:
- 多个事务同时执行 INSERT INTO t SELECT ... LIMIT 1000,会排队等待
- 监控中常看到 waiting for auto-inc lock on t 等待日志
- 主从复制延迟可能因此加剧(尤其在 STATEMENT 格式下)
- 即使只有一条这样的语句,也会阻塞其他所有 INSERT
innodb_autoinc_lock_mode=2 的真实行为和硬性前提
模式 2 是真正的无锁分配:所有 INSERT 都跳过 AUTO-INC 锁,由全局计数器原子递增。但它不是“开箱即用”的安全选项:
- 必须 设置 binlog_format=ROW,否则 MySQL 启动会报错或降级警告
- 不能 用于需要强顺序 ID 的场景(如下游依赖 ID 连续做分页或排序)
- 允许空洞:事务回滚后已分配的 ID 不回收,但这是设计使然,不是 bug
- 不兼容 MyISAM:该模式仅对 InnoDB 生效,且 MySQL 8.0 已彻底移除 MyISAM 引擎支持
调整后如何验证是否生效?
光改配置不够,得看实际运行时表现:
- 执行 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 值仍可能跳变——这属于正常现象,不代表出错
真正容易被忽略的是:模式 2 下的 ID 分配不可预测,如果你的应用层做了“插入后立刻用刚生成的 ID 做关联查询”并假设它紧邻前一个 ID,这种逻辑会失效;另外,某些分库分表中间件依赖 ID 的单调递增性做路由,切换前务必确认兼容性。











