在新建数据表时,我们一般会考虑为每一张表添加一个自增主键,但时间久了去看记录会发现 ID 并不连续,人为删除记录不在我们的讨论范围,今天来对我遇到导致 MySQL 自增主键 ID 不连续的原因做下汇总。
原因 1:唯一键冲突
还原步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| CREATE TABLE `t1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_a` (`a`) ) ENGINE=InnoDB;
INSERT INTO t1 (a, b) VALUE (1, 1);
INSERT INTO t1 (a, b) VALUE (1, 1);
INSERT INTO t1 (a, b) VALUE (2, 2);
SELECT * FROM t1;
|
执行 S3 会提示 Duplicate entry ‘1’ for key ‘uk_a’,是因为已经存在 (1, 1) 记录,S5 操作查询所有记录,结果如下图,会发现没有 id = 2 这一行,记录 (2, 2) 的 id 为3。

原因 2:事务回滚
还原步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| CREATE TABLE `t2` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_a` (`a`) ) ENGINE=InnoDB;
INSERT INTO t2 (a, b) VALUE (1, 1);
BEGIN; INSERT INTO t2 (a, b) VALUE (2, 2); ROLLBACK;
INSERT INTO t2 (a, b) VALUE (2, 2);
SELECT * FROM t2;
|
S3 操作手动将事务回退,S4 操作再次插入记录 (2, 2),S5 操作查询所有记录,结果如下图,会发现没有 id = 2 这一行,记录 (2, 2) 的 id 为3。

原因 3:批量插入数据
还原步骤:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| CREATE TABLE `t3` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) DEFAULT NULL, `b` int(11) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uk_a` (`a`) ) ENGINE=InnoDB;
INSERT INTO t3 (a, b) VALUE (1, 1);
INSERT INTO t3 (a, b) VALUE (2, 2);
INSERT INTO t3 (a, b) VALUE (3, 3);
INSERT INTO t3 (a, b) VALUE (4, 4);
CREATE TABLE t4 LIKE t3;
INSERT INTO t4 (a, b) SELECT a, b FROM t3;
INSERT INTO t4 (a, b) VALUE (5, 5);
SELECT * FROM t4;
|
S7 操作将 t3 表中的数据插入到 t4 表中,S8 操作插入记录 (5, 5),但它的 id = 8,如下图:

查阅资料,了解到对于批量插入数据(包含的语句类型是 insert … select、replace… select 和 load data 语句)的语句,MySQL 有一个批量申请自增 id 的策略:
- 语句执行过程中,第一次申请自增 id,会分配 1 个;
- 1 个用完以后,这个语句第二次申请自增 id,会分配 2 个;
- 2 个用完以后,还是这个语句,第三次申请自增 id,会分配 4 个;
- 依此类推,同一个语句去申请自增 id,每次申请到的自增 id 个数都是上一次的两倍。
因此,自增主键不能保证连续递增。