导致 MySQL 自增主键 ID 不连续的原因

在新建数据表时,我们一般会考虑为每一张表添加一个自增主键,但时间久了去看记录会发现 ID 并不连续,人为删除记录不在我们的讨论范围,今天来对我遇到导致 MySQL 自增主键 ID 不连续的原因做下汇总。

原因 1:唯一键冲突

还原步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- S1 创建测试表
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;

-- S2 插入记录值:(1, 1)
INSERT INTO t1 (a, b) VALUE (1, 1);

-- S3 再次插入记录值:(1, 1)
INSERT INTO t1 (a, b) VALUE (1, 1);

-- S4 插入记录值:(2, 2)
INSERT INTO t1 (a, b) VALUE (2, 2);

-- S5 查询所有记录
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
-- S1 创建测试表
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;

-- S2 插入记录值:(1, 1)
INSERT INTO t2 (a, b) VALUE (1, 1);

-- S3 插入记录值:(2, 2),手动回退
BEGIN;
INSERT INTO t2 (a, b) VALUE (2, 2);
ROLLBACK;

-- S4 再次插入记录值:(2, 2)
INSERT INTO t2 (a, b) VALUE (2, 2);

-- S5 查询所有记录
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
-- S1 创建测试表
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;

-- S2 插入记录值:(1, 1)
INSERT INTO t3 (a, b) VALUE (1, 1);

-- S3 插入记录值:(2, 2)
INSERT INTO t3 (a, b) VALUE (2, 2);

-- S4 插入记录值:(3, 3)
INSERT INTO t3 (a, b) VALUE (3, 3);

-- S5 插入记录值:(4, 4)
INSERT INTO t3 (a, b) VALUE (4, 4);

-- S6 创建测试表
CREATE TABLE t4 LIKE t3;

-- S7 向 t4 表中插入 t3 表中的记录
INSERT INTO t4 (a, b) SELECT a, b FROM t3;

-- S8 插入记录值:(5, 5)
INSERT INTO t4 (a, b) VALUE (5, 5);

-- S9 查询所有记录
SELECT * FROM t4;

S7 操作将 t3 表中的数据插入到 t4 表中,S8 操作插入记录 (5, 5),但它的 id = 8,如下图:

查阅资料,了解到对于批量插入数据(包含的语句类型是 insert … select、replace… select 和 load data 语句)的语句,MySQL 有一个批量申请自增 id 的策略:

  1. 语句执行过程中,第一次申请自增 id,会分配 1 个;
  2. 1 个用完以后,这个语句第二次申请自增 id,会分配 2 个;
  3. 2 个用完以后,还是这个语句,第三次申请自增 id,会分配 4 个;
  4. 依此类推,同一个语句去申请自增 id,每次申请到的自增 id 个数都是上一次的两倍。

因此,自增主键不能保证连续递增。


导致 MySQL 自增主键 ID 不连续的原因
https://blog.yohlj.cn/posts/61ec8d1a/
作者
Enoch
发布于
2020年1月18日
许可协议