解释 interleaved 模式下并发语句预分配自增值和编号间隔的关系
来源:17golang原创
时间:2026-11-05 11:55:29 295浏览 收藏
先给结论:innodb_autoinc_lock_mode=2(interleaved)允许多个 INSERT-like 语句同时申请自增值,所以编号在不同语句之间交错并不奇怪。它保证的是编号唯一且总体单调递增,不保证每一条并发语句拿到的编号连续;当语句是 bulk insert 时,还可能因为预估和并发分配留下间隔。
这里的“间隔”是自增列的存储结果,不等于数据丢失,也不适合拿来生成严格连续的业务单号。理解这一点后,再看锁模式、插入类型和事务结果,排查就不会混在一起。
先区分唯一、递增和连续
三个词描述的是不同保证:
- 唯一:不同并发语句不会拿到同一个自动生成值。
- 单调递增:后分配的值不会小于先分配的值;这不代表查询结果按插入完成顺序排列。
- 连续:某个语句或整张表的可见编号没有缺口,这是更强的要求。
interleaved 模式主要优化的是并发度。它不再让每个 INSERT-like 语句串行持有表级 AUTO-INC 锁,而是让多个语句同时参与编号分配。因此,“主键没有 100、103”不能直接推出“这一行插入失败”。
三种锁模式到底差在哪里
配置项是启动时的 innodb_autoinc_lock_mode,常见取值为 0、1、2:
| 模式 | 核心行为 | 更适合的判断 |
|---|---|---|
| 0 traditional | 所有 INSERT-like 语句使用表级 AUTO-INC 锁,语句内编号保持连续 | 兼容旧语义、需要 statement-based replication 时优先考虑 |
| 1 consecutive | bulk insert 使用表级锁,已知行数的 simple insert 只在分配阶段取轻量互斥 | 希望兼顾并发和 statement-based replication |
| 2 interleaved | INSERT-like 语句不使用表级 AUTO-INC 锁,允许编号跨语句交错 | 使用 row-based 或 mixed replication、优先并发吞吐时 |
注意:模式 2 是“允许并发分配”,不是“强制每条语句都产生间隔”。如果只有已知行数的 simple insert,单个语句通常仍不会出现间隔;bulk insert 的行数事先不完全确定时,风险才明显。

为什么 bulk insert 会出现预分配间隔
以 INSERT ... SELECT 或 LOAD DATA 为例,InnoDB 在语句开始时可能不知道最终要插入多少行。并发模式下,分配器会在多个语句之间交错提供编号;当某个 bulk insert 先拿到一段估计区间、实际只使用其中一部分时,未使用的编号就不会回收给下一条语句。
可以用一个抽象场景理解,而不要把下面的数字当作固定复现结果:
-- 建立一个用于观察自增列的示例表;业务字段不参与编号分配
CREATE TABLE orders_demo (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
source_name VARCHAR(32) NOT NULL
) ENGINE = InnoDB;
-- bulk insert 的行数来自查询,分配器在处理过程中可能无法预先知道最终行数
INSERT INTO orders_demo (source_name)
SELECT source_name FROM import_stage;
-- 查看实际落盘的编号;结果重点看 id 是否有间隔,不要假设按提交顺序排列
SELECT id, source_name
FROM orders_demo
ORDER BY id;
如果另一条 INSERT-like 语句在第一条处理期间也申请编号,它拿到的值可能落在前一条语句最终写入的编号之间。于是你会看到“单条语句生成的行并不连续”,但所有已经分配的值仍然保持唯一和递增。
编号间隔要拆成三种原因
排查时建议分别问三个问题:
- 是否有并发 bulk insert? 如果有,interleaved 模式下跨语句交错和预分配间隔是正常可能性。
- 是否是 mixed-mode insert? 同一条多行 INSERT 同时显式提供部分自增值时,自动分配的数量可能超过实际使用数量。
- 是否发生过回滚? 只要自增值已经分配,即使语句或事务后来失败并回滚,这些编号也不会被复用。
第三种原因并非 interleaved 独有。传统模式和 consecutive 模式同样会因为回滚产生丢失的自增值;删除数据也会让查询结果看起来不连续,但那属于数据生命周期问题,不是分配器预留问题。

复制模式决定能不能直接用 2
如果使用 statement-based replication,副本需要按语句重放并得到可预测的自增值;这时应在源库和副本使用 0 或 1,并保持配置一致。interleaved 允许并发语句交错,按语句重放时可能得到不同分配顺序,因此不适合这种复制方式。
如果使用 row-based replication,副本关注的是行变化而不是重新执行语句的顺序,三种锁模式都可以安全使用。mixed format 对不适合 statement-based 的语句会采用行方式,也可以按实际复制策略评估。
| 现象或约束 | 先看什么 | 判断方向 |
|---|---|---|
| 高并发导入吞吐优先 | 是否有 row-based/mixed replication | 满足条件时考虑模式 2,接受编号不连续 |
| 必须按语句可预测地重放 | binlog_format 与副本配置 | 选择模式 0 或 1,并保持源副本一致 |
| 业务要求连续票号 | 是否把 AUTO_INCREMENT 当业务编号 | 重新设计独立的业务序列,不要靠改锁模式补连续性 |
一条实用的判断口诀
看到自增列有空洞,先查“并发 bulk insert、mixed-mode、回滚、删除”四件事;看到 interleaved,不要只问“为什么不连续”,而要问“复制格式是否允许、业务是否真的需要连续”。
对普通主键来说,唯一性和并发吞吐往往比连续性更重要。只有当编号承担票据、发票或外部序号职责时,才应该单独设计可审计、可补偿的业务编号机制。
常见追问
interleaved 会让主键重复吗?
正常的 InnoDB 自增分配保证并发生成值不重复;间隔和重复是两个不同问题。若出现重复,应另查显式写入、数据类型上限或表结构约束。
把锁模式改成 0 能消除所有间隔吗?
不能。模式 0 主要保证语句分配的连续性,但回滚、删除以及显式混合插入仍可能留下间隔。
能否用 MAX(id)+1 生成连续编号?
不建议在并发写入中这样做。它会把编号生成变成需要额外锁和冲突处理的业务逻辑,不能替代 InnoDB 的自增机制。
-
205 收藏
-
197 收藏
-
203 收藏
-
291 收藏
-
260 收藏
-
368 收藏
-
148 收藏
-
102 收藏
-
137 收藏
-
488 收藏
-
428 收藏
-
152 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习