面试题:MySQL 自增主键一定是连续的吗?

文章目录

  • 测试环境:
  • 一、自增值的属性特征:
    • 1. 自增主键值是存储在哪的?
    • 2. 自增主键值的修改机制?
  • 二、新增语句自增主键是如何变化的:
  • 三、自增主键值不连续情况:(唯一主键冲突)
  • 四、自增主键值不连续情况:(事务回滚)
  • 五、自增主键值不连续情况:(批量插入)
  • 六、自增主键值的优化
    • 1.什么是自增锁
    • 2.自增锁有哪些优化
  • 七、MySQL8.0做了哪些优化


测试环境:

MySQL版本:8.0

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

在这里插入图片描述

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


一、自增值的属性特征:

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

MySQL5.7版本

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

MySQL8.0之后版本

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

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

图片

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); 

流程图如下所示

图片

流程步骤:

  • 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语句时

insert into t values(null, 1, 1); 

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

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

图片

例如:

  • 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 的策略:

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

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

insert into t values(null, 1,1);
insert into t values(null, 2,2);
insert into t values(null, 3,3);
insert into t values(null, 4,4);
create table tt like t;
insert into tt(c,d) select c,d from t;insert into tt values(null, 5,5);

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

图片

六、自增主键值的优化

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 这种批量插入数据的场景时,既能提升并发性,又不会出现数据一致性问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/583417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uniapp:全局消息是推送,实现app在线更新,WebSocket,apk上传

全局消息是推送&#xff0c;实现app在线更新&#xff0c;WebSocket 1.在main.js中定义全局的WebSocket2.java后端建立和发送WebSocket3.通知所有用户更新 背景&#xff1a; 开发人员开发后app后打包成.apk文件&#xff0c;上传后通知厂区在线用户更新app。 那么没在线的怎么办&…

使用electron属性实现保存图片并获取图片的磁盘路径

在普通的网页开发中&#xff0c;JavaScript由于安全性的考虑&#xff0c;通常是无法直接获取到客户端的磁盘路径的。浏览器出于隐私和安全原因对此类信息进行了限制。 在浏览器环境下&#xff0c;JavaScript主要通过Web APIs来与浏览器进行交互&#xff0c;而这些API通常受到浏…

【北亚服务器数据恢复】ZFS文件系统服务器ZPOOL下线的数据恢复案例

服务器数据恢复环境&#xff1a; 服务器中有32块硬盘&#xff0c;组建了3组RAIDZ&#xff0c;部分磁盘作为热备盘。zfs文件系统。 服务器故障&#xff1a; 服务器运行中突然崩溃&#xff0c;排除断电、进水、异常操作等外部因素。工作人员将服务器重启后发现无法进入操作系统。…

IPD-PDP产品开发流程-PDT产品开发计划Charter文档模板(word)2

书接上回&#xff0c;继续为大家分享PDT的产品开发计划Charter模板的主要内容。 据华研荟了解&#xff0c;大部分国内的企业在推行IPD的时候就直接像华为一样&#xff0c;把开发计划&#xff08;任务书&#xff09;叫做Charter&#xff0c;而不翻译为中文。其实这也是一种很好…

水果软件2024FL Studio21.3mac苹果中文版

FL STUDIO21发布&#xff0c;提供您一直在等待的出色工作流程功能。通过新效果、多个播放列表曲目选择和无所畏惧的撤消一切编辑&#xff0c;将您的音乐带入2024年。FL Studio21中文完整版是一个功能齐全、开放式架构的PC音乐创作和制作环境。它具有基于音乐音序器的图形用户界…

STL——list容器

目录 1.list基本概念 2.list构造函数 3.list赋值和交换 4.list大小操作 5.list插入和删除 6.list数据存取 7.list反转和排序 8.排序案例 1.list基本概念 功能&#xff1a;将数据进行链式存储。 链表&#xff08;list&#xff09;是一种物理存储单元上非连续的存储结构&…

StringBuilder、StringBuffer

StringBuilder StringBuilder代表可变字符串对象&#xff0c;相当于是一个容器&#xff0c;它里面装的字符串是可以改变的&#xff0c;就是用来操作字符串的。好处&#xff1a;StringBuilder比String更适合做字符串的修该操作&#xff0c;效率会更高&#xff0c;代码也会更简洁…

计算机网络概述(上)——“计算机网络”

各位CSDN的uu们好呀&#xff0c;好久没有更新小雅兰的计算机网络的专栏啦&#xff0c;而且期末考试也要考计算机网络&#xff0c;所以&#xff0c;小雅兰就来写计算机网络的内容啦&#xff01;&#xff01;&#xff01;下面&#xff0c;让我们进入计算机网络概述的世界吧&#…

rust中的超时处理

rust中的超时处理 自从 tokio 1.0发布以来&#xff0c;rust的异步开发总算大势已定。尽管没达到标准库的速度&#xff0c;依然挡不住大家的热情。看编程排行榜&#xff0c;增加2倍的开发者。 既生瑜何生亮&#xff0c;感觉go就是小号的rust。 不废话了。背景&#xff1a;之前…

HarmonyOS引导页登陆页以及tabbar的代码说明 登陆页2

代码&#xff1a;这里的prompt.showToast是弹出提示&#xff0c;Extend(TextInput) 的功能是对TextInput做了公用的样式。isShowProgress是用来控制isShowProgress&#xff0c;出来一个等待效果 import prompt from ‘ohos.promptAction’; import router from ‘ohos.router…

Redis缓存雪崩、缓存击穿、缓存穿透

1. 什么是缓存雪崩 当我们提到缓存系统中的问题&#xff0c;缓存雪崩是一个经常被讨论的话题。缓存雪崩是指在某一时刻发生大量的缓存失效&#xff0c;导致瞬间大量的请求直接打到了数据库&#xff0c;可能会导致数据库瞬间压力过大甚至宕机。尤其在高并发的系统中&#xff0c;…

【iptables】增加规则和删除规则

我们在另外一台机器上&#xff0c;使用ping命令&#xff0c;向当前机器发送报文&#xff0c;如下图所示&#xff0c;ping命令可以得到回应&#xff0c;证明ping命令发送的报文已经正常的发送到了防火墙所在的主机&#xff0c;ping命令所在机器IP地址为31.133&#xff08;黑色&a…

如何解决mac无法访问github

确定github能访问的ip地址 点击检测按钮&#xff0c;找到比较快的ip 修改hosts文件&#xff1a;打开终端&#xff0c;输入 open /etc/hosts 后回车&#xff0c;打开mac的文本编辑器 add github.com 140.82.121.4 github.com 199.232.69.194 github.global.ssl.fastly.net …

微服务与人工智能技术的融合

随着人工智能技术的快速发展&#xff0c;越来越多的企业开始关注微服务架构与人工智能技术的结合&#xff0c;以期在市场竞争中获得更大的优势。本文将深入探讨微服务架构与人工智能技术融合的优势、挑战&#xff0c;以及实现这一融合的最佳实践和方法。 首先&#xff0c;让我们…

NCNN环境部署及yolov5pt转ncnn模型转换推理

该内容还未完整&#xff0c;笔记内容&#xff0c;持续补充。 〇开发环境版本 vs2022 cmake3.21.1 ncnn20231027发行版 yolov5s v6.2 vunlkan1.2.198.1 Protobuf3.20.0 Opencv3.4.1 一、模型转换 yolov5s v6.2训练的pt模型&#xff0c;直接导出tourchscript&#xff0c…

ubuntu 开机自报IP地址(用于无屏幕小车-远程连接)

目录 1.环境安装2.代码3.打包成可执行文件4.开启开机自启 1.环境安装 sudo apt-get install espeak #先安装这个库 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pyttsx32.90 #再安装pyttsx3 pyinstaller pip install -i https://pypi.tuna.tsinghua.edu.cn/si…

C语言实例_生成6位数的随机密码

一、前言 随着数字化时代的到来&#xff0c;人们在各个方面需要使用密码来保护个人隐私和敏感信息的安全。为了确保密码的安全性&#xff0c;密码应该是足够强大和难以猜测的&#xff0c;这就需要密码生成器来帮助用户生成高强度的随机密码。 随机密码生成器是一种计算机程序…

P1019 [NOIP2000 提高组] 单词接龙 刷题笔记

P1019 [NOIP2000 提高组] 单词接龙 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路来自 大佬 Chardo 的个人中心 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 匹配 &#xff1a; 将 第一个字符串末尾 和第二个字符串第一个开始匹配 如果 j<i这段走完了 flag还没…

ffmpeg两种windows版本区别说明

版本一 必须拷贝exe和dll文件才能使用&#xff0c;如果缺少dll则exe不正正常执行 如果缺少dll &#xff0c;执行 exe会报错如下 版本2 直接拷贝exe就能使用&#xff0c;没有依赖的环境

Power BI - 5分钟学习合并文件

每天5分钟&#xff0c;今天介绍Power BI合并文件 什么是合并文件&#xff1f; 合并文件就是将具有相同架构的多个文件合并到单个逻辑表中。 如果要合并同一文件夹中的所有文件时&#xff0c;此功能非常有用。 例如&#xff0c;如果你有一个文件夹&#xff0c;其中包含公司的所…