MySQL自增主键一定是连续的吗?

测试环境:
MySQL版本:8.0
数据库表:T (主键id,唯一索引c,普通字段d)

MySQL自增主键一定是连续的吗?

文章插图
如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的 。但实际上,这样的假设是错的,因为自增主键不能保证连续递增 。
一、自增值的属性特征
1. 自增主键值是存储在哪的?
MySQL5.7版本
在 MySQL 5.7 及之前的版本,自增值保存在内存里,并没有持久化 。每次重启后 , 第一次打开表的时候 , 都会去找自增值的最大值 max(id),然后将 max(id)+1 作为这个表当前的自增值 。
MySQL8.0之后版本
在 MySQL 8.0 版本,将自增值的变更记录在了 redo log 中,重启的时候依靠 redo log 恢复重启之前的值 。
可以通过看表详情查看当前自增值,以及查看表参数详情AUTO_INCREMENT值(AUTO_INCREMENT就是当前数据表的自增值)
MySQL自增主键一定是连续的吗?

文章插图
2. 自增主键值的修改机制?
在表t中,我定义了主键id为自增值,在插入一行数据的时候 , 自增值的行为如下:
1)如果插入数据时 id 字段指定为 0、null 或未指定值,那么就把这个表当前的 AUTO_INCREMENT 值填到自增字段;
2)如果插入数据时 id 字段指定了具体的值,就直接使用语句里指定的值 。
根据要插入的值和当前自增值的大小关系,自增值的变更结果也会有所不同 。假设,某次要插入的值是 X,当前的自增值是 Y 。
1)如果 X<Y,那么这个表的自增值不变;
2)如果 X≥Y,就需要把当前自增值修改为新的自增值 。
二、新增语句自增主键是如何变化的
我们执行以下SQL语句,来观察自增主键是如何进行变化的
insert into t values(null, 1, 1);
流程图如下所示:
MySQL自增主键一定是连续的吗?

文章插图
流程步骤:
1、AUTO_INCREMENT=1(表示下一次插入数据时,如果需要自动生成自增值,会生成 id=1 。)
2、insert into t values(null, 1, 1)(执行器调用 InnoDB 引擎接口写入一行,传入的这一行的值是 (0,1,1))
3、get AUTO_INCREMENT=1(InnoDB 发现用户没有指定自增 id 的值 , 获取表 t 当前的自增值 1 )
4、AUTO_INCREMENT=2 insert into t values(1, 1, 1)(将传入的行的值改成 (1,1,1),并把自增值改为2)
5、insert (1,1,1) 执行插入操作,至此流程结束
大家可以发现,在这个流程当中是先进行自增值的+1 , 在进行新增语句的执行的 。大家可以发现这个操作并没有进行原子操作,如果SQL语句执行失败 , 那么自增是不是就不会连续了呢?
三、自增主键值不连续情况:(唯一主键冲突)
当我执行以下SQL语句时
insert into t values(null, 1, 1);
第一次我们可以进行新增成功,根据自增值的修改机制 。如果插入数据时 id 字段指定为 0、null 或未指定值,那么就把这个表当前的 AUTO_INCREMENT 值填到自增字段;
当我们第二次在执行以下SQL语句时,就会出现错误 。因为我们表中c字段是唯一索引,会出现Duplicate key error错误导致新增失败 。
例如:
1、AUTO_INCREMENT=2(表示下一次插入数据时 , 如果需要自动生成自增值,会生成 id=2 。)
2、insert into t values(null, 1, 1)(执行器调用 InnoDB 引擎接口写入一行,传入的这一行的值是 (0,1,1))
3、get AUTO_INCREMENT=2(InnoDB 发现用户没有指定自增 id 的值,获取表 t 当前的自增值 2 )
4、AUTO_INCREMENT=3 insert into t values(2, 1, 1)(将传入的行的值改成 (2,1,1),并把自增值改为3)
5、insert (2,1,1) 执行插入操作,由于已经存在 c=1 的记录 , 所以报 Duplicate key error,语句返回 。
可以看到,这个表的自增值改成 3,是在真正执行插入数据的操作之前 。这个语句真正执行的时候,因为碰到唯一键 c 冲突,所以 id=2 这一行并没有插入成功,但也没有将自增值再改回去 。所以,在这之后,再插入新的数据行时,拿到的自增 id 就是 3 。也就是说,出现了自增主键不连续的情况 。
四、自增主键值不连续情况:(事务回滚)
其实事务回滚原理也和上面一样,都是因为异常导致新增失败,但是自增值没有进行回退 。
五、自增主键值不连续情况:(批量插入)
批量插入数据的语句 , MySQL 有一个批量申请自增 id 的策略:


推荐阅读