mysql的innodb自增主键为什么不是连续的

图1
图1中是表t原有的数据,这个时候我们执行show create table t会看到如下输出,如图二所示现在的自增值是2,也就是下一个不指定主键值的插入的数据的主键就是2

图2
Innodb引擎的自增值,是保存在内存中的,并且到了mysql8.0版本后,才有了“自增值持久化”的能力,也就是才实现了"如果发生重启,表的自增值可以恢复为mysql重启前的值"
也就说在mysql5.7及之前的版本,自增值保存在内存中,并没有持久化,每次重启后,第一次打开表的时候,都会去找自增值的最大值max(id),然后讲max(id)+1作为当前表的自增值
举例来说,如果一个表中当前数据行的最大id=3,自增值=4,这个时候我们删除id=3的数据后,自增值还是=4,但是这个时候如果马上重启,重启后这个表的自增值就会变成3,
我们可以做个实验:


这个时候的自增值=4

我们删掉了id=3的数据
然后我们在查询一下自增值,我们可以看到这个时候的自增值还是4

然后我们在重启以后在查询一下,可以看到这个时候的自增值就是3了

在mysql8.0版本,将自增值的变更记录在了redo log中,重启的时候依靠redo log恢复重启之前的值
接下来我们在做个实验说明一下自增值为啥不是连续的,我们刚才建的表t的c字段我加了唯一索引,现在我们表中的自增值应该是3对吧,因为刚才我重启过了,然后我们执行INSERT INTO t VALUES(NULL,2,3)
这条语句,会报错插入失败,这条语句的执行流程是这样的
1,执行器调用innodb引擎接口写入一行,传入的这一行的值是(0,2,3);
2,innodb发现用户没有指定自增id的值,获取表t当前的自增值3;
3,将传入的行的值改成(3,1,1);
4,将表的自增值改成4;
5,继续执行插入数据操作,由于已经存在C=2的记录,所以报Duplicate key eror,语句返回

然后我们在查询一下自增值,看到了没有,现在的自增值已经变成了4,也就说上面这条语句插入失败以后,自增值没有回滚,这样下次我们在插入数据的时候的主键值就是4,就会造成我们的主键值不一致

所以说,唯一键冲突是导致自增主键id不连续的第一种原因
同样的,事务回滚也会产生类似的现象,这就是第二种原因
你可能会问,为什么在出现唯一键冲突或者事务回滚的时候,mysql没有把表t的自增值改回去呢?如果把表t的当前自增值从4改回3,再插入新数据的时候,不就可以生成id=3的一行数据了吗?
其实,mysql这么设计是为了提升性能,接下来,分析一下这个设计思路,看看自增值为什么不能回退
假设有两个并行执行的事务,在申请自增值的时候,为了避免两个事务申请到相同的自增id,肯定要加锁,然后顺序申请
1.假设事务A申请到了id=2,事务B申请到id=3,那么这时候表t的自增值是4,之后继续执行
2.事务B正确提交了,但事务A出现了唯一键冲突
3.如果允许事务A把自增id回退,也就是把表t的当前自增值改成2,那么就会出现这样的情况:表里面已经有id=3的行,而当前的自增id值是2
4.接下来,继续执行的其他事务就会申请到id=2,然后在申请到id=3,这时候,就会出现插入语句报错“主键冲突"
而为了解决这个主键冲突,有两种方法:
1,每次申请id之前,先判断表里面是否已经存在这个id,如果存在,就跳过这个id,但是,这个方法的成本很高,因为,本来申请id是一个很快的操作,现在还要再去主键索引树上判断id是否存在
2,把自增id的锁范围扩大,必须等到一个事务执行完成并提交,下一个事务才能再申请自增id,这个方法的问题,就是锁的粒度太大,系统并发能力大大下降
可见,这两个方法都会导致性能问题,造成这些麻烦的罪魁祸首,就是我们假设的这个”允许自增id回退“的前提导致的,
因此,innodb放弃了这个设计,语句执行失败也不回退自增id,也正是因为这样,所有才只保证了自增id是递增的,但不保证是连续的。
mysql的innodb自增主键为什么不是连续的的更多相关文章
- java面试一日一题:mysql中的自增主键
问题:请讲下mysql中的自增主键 分析:该问题主要考察对mysql中自增主键的掌握,使用场景及如何设置 回答要点: 主要从以下几点去考虑 1.什么自增主键 2.使用场景是什么: 3.innodb_a ...
- INNODB自增主键的一些问题 vs mysql获得自增字段下一个值
今天发现 批量插入下,自增主键不连续了....... InnoDB AUTO_INCREMENT Lock Modes This section describes the behavior of A ...
- INNODB自增主键的一些问题
背景: 自增长是一个很常见的数据属性,在MySQL中大家都很愿意让自增长属性的字段当一个主键.特别是InnoDB,因为InnoDB的聚集索引的特性,使用自增长属性的字段当主键性能更好,这里要说明下自增 ...
- mycat分布式mysql中间件(自增主键)
一.全局序列号 全局序列号是MyCAT提供的一个新功能,为了实现分库分表情况下,表的主键是全局唯一,而默认的MySQL的自增长主键无法满足这个要求.全局序列号的语法符合标准SQL规范,其格式为:nex ...
- 《Mysql - 自增主键为何不是连续的?》
一:自增主键是连续的么? - 自增主键不能保证连续递增. 二:自增值保存在哪里? - 当使用 show create table `table_name`:时,会看到 自增值,也就是 AUTO_INC ...
- Innodb自增主键与sql_mode
1.自增主键 1.设置自增主键 建表设置自增主键,设置自增主键需要唯一约束,否则会报错.(即指定列数据唯一) mysql> create table test_zz(id int auto_in ...
- MySQL 中的自增主键
MySQL 的主键可以是自增的,那么如果在断电重启后新增的值还会延续断电前的自增值吗?自增值默认为1,那么可不可以改变呢?下面就说一下 MySQL 的自增值. 特点 保存策略 1.如果存储引擎是 My ...
- mysql 自增主键为什么不是连续的?
由于自增主键可以让主键索引尽量地保持递增顺序插入,避免了页分裂,因此索引更紧凑 MyISAM 引擎的自增值保存在数据文件中 nnoDB 引擎的自增值,其实是保存在了内存里,并且到了 MySQL 8.0 ...
- MySQL 插入与自增主键值相等的字段 与 高并发下保证数据准确的实验
场景描述: 表t2 中 有 自增主键 id 和 字段v 当插入记录的时候 要求 v与id 的值相等(按理来说这样的字段是需要拆表的,但是业务场景是 只有某些行相等 ) 在网上搜的一种办法是 先获取 ...
随机推荐
- chkdsk工具怎么修复
对于一些硬盘存储问题,即使windows自带的系统工具,也可以将其修复,比如chkdsk程序.请阅读下文,了解如何使用chkdsk来修复简单的硬盘问题. 工具/原料 windows7 chkdsk 方 ...
- oscache.properties文件配置
1.cache.memory是否使用内存缓存:值为:true或false.默认为true:如设置为false,那cache只能缓存到数据库或硬盘中. 2.cache.capacity缓存的最大数量.默 ...
- [luogu3369]普通平衡树(fhq-treap模板)
解题关键:无旋treap模板. #include<iostream> #include<cstdio> #include<cstring> #include< ...
- 用Eclipse Memory Analyzer查找内存泄露
写在CSDN里面了 http://blog.csdn.net/dayulxl/article/details/78164301
- Angular23 loading组件、路由配置、子路由配置、路由懒加载配置
1 需求 由于Angular是单页面的应用,所以在进行数据刷新是进行的局部刷新:在进行数据刷新时从浏览器发出请求到后台响应数据是有时间延迟的,所以在这段时间就需要进行遮罩处理来提示用户系统正在请求数据 ...
- 18-printf(*)的输出格式
#include <bits/stdc++.h> using namespace std; int main(){ for(int i = 0; i < 26; i++){ cout ...
- 重置CentOS6.5的登录口令
早先在虚拟机Vmware里安装了一台CentOS6.5,现在想登录,发现无论怎么输入登录口令都不正确,以至于无法登录. 查阅网上资料,可用下面步骤里的方法重置登录口令,在此记录. 1.启动机器,出现下 ...
- Windows cmd 快捷操作
复制当前文件夹下符合条件的文件名字到文件 dir /B *-gd.dll > debug /B是只显示文件名,不包含所在路径 复制当前文件夹下文件到另外的地方 xcopy /s/d *-gd.d ...
- js-简单的作业
作业 1 将课堂 偶数奇数和 猜数字游戏 电话银行转for循环 2 编写 “个人所得税计算器”函数 10000 计算个税的方法: 3500 以下免征 6500 3500 ~ 5000 部分 缴纳 3% ...
- win7,64bit下的OpenGL着色语言(glsl)开发环境配置(原)
一.环境准备: 系统环境win7,64位,双显卡:集成显卡+gt540m,gt540建议下载最新的驱动,可以支持到opengl4.3标准,一般双显的笔记本,程序默认启用的是集显,我机器的集显驱动有点老 ...