0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

dyquk4xk2p3d 来源:CSDN 2023-06-11 11:35 次阅读

测试环境:

MySQL版本:8.0

数据库表:T (主键id,唯一索引c,普通字段d)

27e06496-05e9-11ee-962d-dac502259ad0.png

如果你的业务设计依赖于自增主键的连续性,这个设计假设自增主键是连续的。但实际上,这样的假设是错的,因为自增主键不能保证连续递增。

一、自增值的属性特征:

1. 自增主键值是存储在哪的?

MySQL5.7版本

在 MySQL 5.7 及之前的版本,自增值保存在内存里,并没有持久化。每次重启后,第一次打开表的时候,都会去找自增值的最大值max(id),然后将max(id)+1作为这个表当前的自增值。

MySQL8.0之后版本

在 MySQL 8.0 版本,将自增值的变更记录在了redo log中,重启的时候依靠redo log恢复重启之前的值。

可以通过看表详情查看当前自增值,以及查看表参数详情AUTO_INCREMENT值(AUTO_INCREMENT就是当前数据表的自增值)

27eca3dc-05e9-11ee-962d-dac502259ad0.png

2. 自增主键值的修改机制?

在表t中,我定义了主键id为自增值,在插入一行数据的时候,自增值的行为如下:

如果插入数据时 id 字段指定为 0、null 或未指定值,那么就把这个表当前的AUTO_INCREMENT值填到自增字段;

如果插入数据时 id 字段指定了具体的值,就直接使用语句里指定的值。

根据要插入的值和当前自增值的大小关系,自增值的变更结果也会有所不同。假设,某次要插入的值是 X,当前的自增值是 Y。

如果 X

如果 X≥Y,就需要把当前自增值修改为新的自增值。

二、新增语句自增主键是如何变化的:

我们执行以下SQL语句,来观察自增主键是如何进行变化的

insertintotvalues(null,1,1);

流程图如下所示

27fc6628-05e9-11ee-962d-dac502259ad0.png

流程步骤:

AUTO_INCREMENT=1(表示下一次插入数据时,如果需要自动生成自增值,会生成 id=1。)

insert into t values(null, 1, 1)(执行器调用 InnoDB 引擎接口写入一行,传入的这一行的值是 (0,1,1))

get AUTO_INCREMENT=1(InnoDB 发现用户没有指定自增 id 的值,获取表 t 当前的自增值 1 )

AUTO_INCREMENT=2 insert into t values(1, 1, 1)(将传入的行的值改成 (1,1,1),并把自增值改为2)

insert (1,1,1)执行插入操作,至此流程结束

大家可以发现,在这个流程当中是先进行自增值的+1,在进行新增语句的执行的。大家可以发现这个操作并没有进行原子操作,如果SQL语句执行失败,那么自增是不是就不会连续了呢?

三、自增主键值不连续情况:(唯一主键冲突)

当我执行以下SQL语句时

insertintotvalues(null,1,1);

第一次我们可以进行新增成功,根据自增值的修改机制。如果插入数据时 id 字段指定为 0、null 或未指定值,那么就把这个表当前的AUTO_INCREMENT值填到自增字段;

当我们第二次在执行以下SQL语句时,就会出现错误。因为我们表中c字段是唯一索引,会出现Duplicate key error错误导致新增失败。

280643aa-05e9-11ee-962d-dac502259ad0.png

例如:

AUTO_INCREMENT=2(表示下一次插入数据时,如果需要自动生成自增值,会生成 id=2。)

insert into t values(null, 1, 1)(执行器调用 InnoDB 引擎接口写入一行,传入的这一行的值是 (0,1,1))

get AUTO_INCREMENT=2(InnoDB 发现用户没有指定自增 id 的值,获取表 t 当前的自增值 2 )

AUTO_INCREMENT=3 insert into t values(2, 1, 1)(将传入的行的值改成 (2,1,1),并把自增值改为3)

insert (2,1,1)执行插入操作,由于已经存在 c=1 的记录,所以报Duplicate key error,语句返回。

可以看到,这个表的自增值改成 3,是在真正执行插入数据的操作之前。这个语句真正执行的时候,因为碰到唯一键 c 冲突,所以 id=2 这一行并没有插入成功,但也没有将自增值再改回去。所以,在这之后,再插入新的数据行时,拿到的自增 id 就是 3。也就是说,出现了自增主键不连续的情况。

四、自增主键值不连续情况:(事务回滚)

其实事务回滚原理也和上面一样,都是因为异常导致新增失败,但是自增值没有进行回退。

五、自增主键值不连续情况:(批量插入)

批量插入数据的语句,MySQL 有一个批量申请自增 id 的策略:

语句执行过程中,第一次申请自增 id,会分配 1 个;

1 个用完以后,这个语句第二次申请自增 id,会分配 2 个;

2 个用完以后,还是这个语句, 第三次申请自增 id,会分配 4 个;

依此类推,同一个语句去申请自增 id,每次申请到的自增 id 个数都是上一次的两倍。

执行以下SQL语句(在表t中先新增了4条数据,在创建表tt把表t数据进行批量新增)

insertintotvalues(null,1,1);
insertintotvalues(null,2,2);
insertintotvalues(null,3,3);
insertintotvalues(null,4,4);
createtablettliket;
insertintott(c,d)selectc,dfromt;

insertintottvalues(null,5,5);

第一次申请到了 id=1,第二次被分配了 id=2 和 id=3, 第三次被分配到 id=4 到 id=7。当我们再执行insert into t2 values(null, 5,5),实际上插入的数据就是(8,5,5),出现了自增主键不连续的情况。

2812d1e2-05e9-11ee-962d-dac502259ad0.png

六、自增主键值的优化

1.什么是自增锁

自增锁是一种比拟非凡的表级锁。并且在事务向蕴含了AUTO_INCREMENT列的表中新增数据时就会去持有自增锁,假如事务 A 正在做这个操作,如果另一个事务 B 尝试执行 INSERT语句,事务 B 会被阻塞住,直到事务 A 开释自增锁。

2.自增锁有哪些优化

在 MySQL 5.0 版本的时候,自增锁的范围是语句级别。也就是说,如果一个语句申请了一个表自增锁,这个锁会等语句执行结束以后才释放。显然,这样设计会影响并发度。在MySQL 5.1.22 版本引入了一个新策略,新增参数innodb_autoinc_lock_mode,默认值是 1。

传统模式(Traditional)

这个参数的值被设置为 0 时,表示采用之前 MySQL 5.0 版本的策略,即语句执行结束后才释放锁;

传统模式他可以保证数据一致性,但是如果有多个事务并发的执行 INSERT 操作,AUTO-INC的存在会使得 MySQL 的性能略有降落,因为同时只能执行一条 INSERT 语句。

间断模式(Consecutive)

这个参数的值被设置为 1 时:普通 insert 语句,自增锁在申请之后就马上释放;类似insert … select这样的批量插入数据的语句,自增锁还是要等语句结束后才被释放;

间断模式他可以保证数据一致性,但是如果有多个事务并发的执行 INSERT 批量操作时,就会进行锁等待状态。如果我们业务插入数据量很大时,这个时候MySQL的性能就会大大下降。

穿插模式(Interleaved)

这个参数的值被设置为 2 时,所有的申请自增主键的动作都是申请后就释放锁。

穿插模式他没有进行任何的上锁设置。在一定情况下是保证了MySQL的性能,但是他无法保证数据的一致性。如果我们在穿插模式下进行主从复制时,如果你的binlog格式不是row格式,主从复制就会出现不一致。

七、MySQL8.0做了哪些优化

在MySQL8.0之后版本,已经默认设置为innodb_autoinc_lock_mode=2,binlog_format=row.。这样更有利与我们在insert … select这种批量插入数据的场景时,既能提升并发性,又不会出现数据一致性问题。





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • SQL
    SQL
    +关注

    关注

    1

    文章

    760

    浏览量

    44076
  • MYSQL数据库
    +关注

    关注

    0

    文章

    95

    浏览量

    9382

原文标题:被问懵了:MySQL 自增主键一定是连续的吗?

文章出处:【微信号:良许Linux,微信公众号:良许Linux】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    怎么简单实现由Labview读取的串口数据写入mysql5.7数据库中?

    怎么简单实现由Labview读取的串口数据写入mysql5.7数据库中? 已实现:串口数据的接收处理 mysql5.7的安装(已测试数据库正常运行) 愿付费解决此问题(QQ:8
    发表于 01-11 22:05

    #硬声创作季 【MySQL调优】为什么推荐使用整型的主键而不是UUID

    数据库MySQL
    Mr_haohao
    发布于 :2022年09月14日 07:41:14

    阿里云mysql数据库怎么设置主键和时间格式怎么显示时分秒?

    `需要将测试的数据保存到阿里云mysql数据库上,利用NI的数据库工具包怎么创建表实现主键?还有保存的时间数据只显示日期,不显示时分秒(用DB Tools Format Datet
    发表于 11-13 10:39

    Python常用运算写法

    在学习任何种编程语言,运算方法的学习是不可避免的,其中运算符++的使用也是其中的重点,很多人容易弄不明白其用法,尤其是在Python中,其用法更加的不同!我们可以写个实例来说明
    发表于 04-09 17:45

    labview向oracle插入数据,怎样可以主键1?如果不插入主键的字段,会报插入的数目与表中的数据不相等

    本帖最后由 电子人steve 于 2018-5-23 20:30 编辑 labview向oracle数据库插入数据时,怎样可以主键1啊,服务器数据库表中设置了
    发表于 05-23 18:53

    MySQL表分区类型及介绍

    表分区是将个表的数据按照一定规则水平划分成不同的逻辑块,并分别进行物理存储,这个规则就叫做分区函数,可以有不同的分区规则。通过show plugins语句查看当前MySQL是否支持表分区功能
    发表于 06-29 16:31

    关于MySQL的基础知识简析

    系统环境MAC OS 10.10MySQL版本,5.7.9Mac 安装mysql很简单,官网下载安装包,双击安装就可以了,有几个地方需要注意在Mac下用DMG包新安装mysql,在安装完毕最后
    发表于 11-03 11:50

    21个MySQL表设计的经验准则

    主键设计的话,最好不要与业务逻辑有所关联。有些业务上的字段,比如身份证,虽然是唯的,些开发者喜欢用它来做主键,但是不是很建议哈。主键最好
    的头像 发表于 01-12 10:07 560次阅读

    MySQL主键一定是连续的吗?

    众所周知,主键可以让聚集索引尽量地保持递增顺序插入,避免了随机查询,从而提高了查询效率
    的头像 发表于 02-20 18:06 708次阅读

    MySQL主键一定是连续的吗?

    如果你的业务设计依赖于主键连续性,这个设计假设主键
    的头像 发表于 03-21 16:55 608次阅读

    主键不用随机字符串用什么?主键

    主键不用随机字符串用什么?主键主键就是最佳
    的头像 发表于 05-09 09:04 591次阅读
    <b class='flag-5'>主键</b>不用随机字符串用什么?<b class='flag-5'>主键</b><b class='flag-5'>自</b><b class='flag-5'>增</b>?

    线上MySQLid用尽怎么办?

    MySQLid都定义了初始值,然后不断加步长。虽然自然数没有上限,但定义了表示这个数的字节长度,计算机存储就有上限。
    的头像 发表于 05-22 10:23 489次阅读
    线上<b class='flag-5'>MySQL</b>的<b class='flag-5'>自</b><b class='flag-5'>增</b>id用尽怎么办?

    id的机制不同在mysql的索引结构以及优缺点

    的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯,单机递增),而是推荐连续
    的头像 发表于 06-30 10:19 780次阅读
    id的机制不同在<b class='flag-5'>mysql</b>的索引结构以及优缺点

    MySQL索引的常用知识点

    索引结构:B+树 索引其实是种数据结构 注意B+树是MySQL,索引默认的结构;张表至少有个索引(主键索引),是可以有多个索引的
    的头像 发表于 09-30 16:43 440次阅读

    主键去哪了?---次开发过程中的思考

    TABLE `example_table` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键
    的头像 发表于 09-05 14:12 196次阅读
    <b class='flag-5'>自</b><b class='flag-5'>增</b><b class='flag-5'>主键</b>去哪了?---<b class='flag-5'>一</b>次开发过程中的思考