Mysql中自增主键是如何工作的

自增主键的特点是当表中每新增一条记录时,主键值会根据自增步长自动叠加,通常会将自增步长设置1,也就是说自增主键值是连续的。那么MySQL自增主键值一定会连续吗?今天这篇文章就来说说这个问题,看看什么情况下自增主键会出现不连续?

1.数据准备

drop TABLE increnment_test;
-- 创建包含自增主键的表  
CREATE TABLE increnment_test (  
  id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,  
  col1 INT(11) NOT NULL,
  col2 INT(11) NOT NULL,
  col3 INT(11) NOT NULL,
  UNIQUE KEY (col1)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4;

2.自增值存储机制

1.MyISAM 引擎的自增值保存在数据文件中。

2.Innodb 引擎

● 在 MySQL 5.7 及之前的版本,自增值保存在内存里。每次重启后,第一次打开表的时候,都会去找自增值的最大值 max(id),然后将 max(id) + 1 作为这个表当前的自增值。
● 在 MySQL 8.0 版本,将自增值的变更记录在了 redo log 中,重启的时候依靠 redo log 恢复重启之前的值。

-- 1.往increnment_test表中插入2条数据
INSERT INTO increnment_test (col1, col2, col3) VALUES    
    (1, 1, 1),    
    (2, 2, 2);

-- 2.此时id值为2,AUTO_INCREMENT值为3。我们删除id为2的记录
delete from increnment_test where id = 2;

-- 3.立马重启实例,重新插入记录。此时id为2。
INSERT INTO increnment_test (col1, col2, col3) VALUES    
		(2, 2, 2);

-- 4.不重启实例,删除id为2的记录后,重新插入数据,id应为3。

3.自增值修改机制

在MySQL中,可以使用AUTO_INCREMENT关键字来指定ID字段为自增ID字段。当向表中插入一条记录时,MySQL将自动为该记录的ID字段生成一个新的自增ID值,并将该值保存到该记录的ID字段中。具体规则如下:

● 如果ID字段未指定具体的值,则将当前AUTO_INCREMENT值并将其填入自增字段,并生成新的自增值
● 如果ID字段已指定具体的值,则直接使用指定的值作为 ID 字段的值,而不会生成新的 AUTO_INCREMENT 值。

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

● 如果插入值小于当前自增值,那么直接使用插入值填入ID字段,自增值不变;
● 如果插入值大于当前自增值,那么除了直接使用插入值填入ID字段外,自增值需修改为插入值+1;

上述”插入值+1‘不是直接使用”插入值“+1,是auto_increment_offset(自增初始值)以 auto_increment_increment(自增步长)为步长,持续累加,直到找到大于插入值的值,作为新的自增值。

4.自增值修改流程

上述我们了解了自增值的存储机制与修改机制,自增值修改是在哪个环境呢?那需要了解自增值修改流程。

INSERT INTO increnment_test (col1, col2, col3) 
 VALUES (3, 3, 3);

以上述SQL为例,我们假如数据库里已经有2条数据了,它的执行流程如下:

● 执行器调用 InnoDB 引擎接口将分析器优化后的SQL传入,并将值(3,3,3)一起传过去。
● InnoDB 发现用户没有指定自增 id列,会先获取表increnment_test当前的自增值3;
● 将ID列补充完整,并且将自增值填入(3,3,3,3)
● 然后将表的自增值改成4;
● 继续执行插入数据操作;

自增字段值的生成是由存储引擎自动完成的,而不是由优化器完成的。因此,在执行 SQL 语句时,即使未指定自增字段列,也不会对性能产生任何影响。

5.导致自增值不连续的原因

5.1 唯一键冲突

比如increnment_test中已经存在了col1为3的记录,我们继续插入col1为3的记录,此时会出现唯一键冲突插入报错,但是没有将自增值再改回去。重新插入col1为4的值,此时对应的id为5;
如下操作流程:

5.1.1.检查数据

select * from increnment_test;

在这里插入图片描述

5.1.2.插入col1为3的数据

INSERT INTO increnment_test (col1, col2, col3) VALUES    
		(3, 3, 3);

5.1.3.插入col1为4的记录

INSERT INTO increnment_test (col1, col2, col3) VALUES    
		(4, 4, 4);
select * from increnment_test;

在这里插入图片描述

5.2.事务回滚

开启一个事务插入col1为6的数据,然后进行回滚。回滚后重新插入col1为6的记录,此时col1为6对应的id值为7。

BEGIN;    
INSERT INTO increnment_test (col1, col2, col3) VALUES      
    (6, 6, 6);   
ROLLBACK; 

BEGIN;    
INSERT INTO increnment_test (col1, col2, col3) VALUES      
    (6, 6, 6);   
COMMIT;

在这里插入图片描述

5.3.批量插入数据

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

● SQL语句执行过程中,第1次申请自增 id,会分配 1 个;
● 1 个用完以后,第2次申请自增 id,会分配 2 个;
● 2 个用完以后,第3次申请自增 id,会分配 4 个;

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

drop table increnment_test2;
create table increnment_test2 like increnment_test;

INSERT INTO increnment_test2 (col1, col2, col3) SELECT
  col1, col2, col3 FROM increnment_test;

INSERT INTO increnment_test2 (col1, col2, col3)
VALUES (8, 8, 8);  

SELECT * FROM increnment_test2;

在这里插入图片描述

因为increnment_test2表中批量插入了5条数据,按照自增ID的批量申请策略,5条数据分3次进行申请:
第1次:id-1
第2次:id-2、3
第3次:id-4、5、6、7
由于只有5条记录,所以只使用了4、5被浪费了。当我们在次插入数据时,AUTO_INCREMENT从8开始。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MATLAB实现灰色预测

久违了,前段时间由于学习压力大,就没怎么更新MATLAB相关的内容,今天实在学不进去了,换个内容更新一下~ 本贴介绍灰色预测模型,这也是数学建模竞赛常见算法中的一员,和许多预测模型一样——底层原理是根据已…

笔试题之指针结合数组的精讲2

𝙉𝙞𝙘𝙚!!👏🏻‧✧̣̥̇‧✦👏🏻‧✧̣̥̇‧✦ 👏🏻‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - :来于“云”的“羽球人”。…

接口测试 —— requests 的基本了解

● requests介绍及安装 ● requests原理及源码介绍 ● 使用requests发送请求 ● 使用requests处理响应 ● get请求参数 ● 发送post请求参数 ● 请求header设置 ● cookie的处理 ● https证书的处理 ● 文件上传、下载 requests介绍 ● requests是python第三方的HTTP…

python -opencv 中值滤波 ,均值滤波,高斯滤波实战

python -opencv 中值滤波 ,均值滤波,高斯滤波实战 cv2.blur-均值滤波 cv2.medianBlur-中值滤波 cv2.GaussianBlur-高斯滤波 直接看代码吧,代码很简单: import copy import math import matplotlib.pyplot as plt import matp…

对线程的创建

一,概括 二,线程构建方式一(继承Thread类) 三,案例 父类: package Duoxiancheng;public abstract class Name {public static void main(String[] args) {//3,创建一个Thread线程类对象Thr…

【小黑送书—第九期】>>重磅!这本30w人都在看的Python数据分析畅销书:更新了!

想学习python进行数据分析,这本《利用python进行数据分析》是绕不开的一本书。目前该书根据Python3.10已经更新到第三版。 Python 语言极具吸引力。自从 1991 年诞生以来,Python 如今已经成为最受欢迎的解释型编程语言。 pandas 诞生于2008年。它是由韦…

__int128类型movaps指令crash

结论 在使用__int128时,如果__int128类型的内存起始地址不是按16字节对齐的话,有些汇编指令会抛出SIGSEGV使程序crash。 malloc在64位系统中申请的内存地址,是按16字节对齐的,但一般使用时经常会申请一块内存自己切割使用&#…

Selenium浏览器自动化测试框架

介绍 Selenium [1] 是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome&#xff…

vs调试输出,不显示线程已退出

如题:一堆线程退出的信息,招人烦。 其实在vs设置里可以关闭: 工具-->选项-->调试-->输出窗口:

动态跳过测试用例

动态跳过测试用例 说明 我们可以通过指定环境变量来动态判断是否执行指定的测试用例设置环境变量有很多种方法,例如命令行方式,格式:--env keyval1,key2val2 ,若需要指定多个环境变量则需要逗号来隔开,而不是空格 t…

innoDB的缓冲池(Buffer Pool)的工作原理

数据存在磁盘了,总不能次次和磁盘交互吧,所以innoDB有一个缓冲池(Buffer Pool),有了缓冲池后,读写就优先在缓冲池了。读先在缓冲池读,没有再去磁盘加载进缓冲池;写也是先写缓冲池&am…

调试接口速度,打印毫秒数,找出慢的地方,优化

方法的最开头写上 $start_time microtime(true); 然后代码行里 dump(All 1: time ’ . (microtime(true) - $start_time)); dump(All 1.2: time ’ . (microtime(true) - $start_time)); 类似这样的最终打印

[C++] STL_stack queue接口的模拟实现

文章目录 1、stack1.1 stack的介绍1.2.1 stack的构造1.2.2 进、出栈等接口的模拟实现 2、queue2.1 queue的介绍2.2 queue的使用2.2.1 queue构造2.2.2 入、出队等接口的模拟实现 1、stack 1.1 stack的介绍 stack的文档介绍 1. stack是一种容器适配器,专门用在具有…

Linux程序之可变参数选项那些事!

一、linux应用程序如何接收参数? 1. argc、argv Linux应用程序执行时,我们往往通过命令行带入参数给程序,比如 ls /dev/ -l 其中参数 /dev/ 、-l都是作为参数传递给命令 ls 应用程序又是如何接收这些参数的? 通常应用程序都…

thinkphp文件夹生成zip压缩包

一、准备工作&#xff0c;使用phpinfo()查看有没有zip扩展 <?php echo phpinfo(); ?>Thinkphp使用PHP自带的ZipArchive压缩文件或文件夹 显示enabled 说明已经配置好 如果没有安装扩展的&#xff0c;请参照以下方法&#xff1a; 1、下载对应版本的扩展包&#xff1a…

还不知道指针和引用的区别,一篇文章教会你

1、引用的概念 1.引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名 2.编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间 比如:孙悟空&#xff0c;可以叫他孙悟空&#xff0c;也可以叫齐天大圣。本质他们就是一个人 2、引用的定…

opencv- CLAHE 有限对比适应性直方图均衡化

CLAHE&#xff08;Contrast Limited Adaptive Histogram Equalization&#xff09;是一种对比度有限的自适应直方图均衡化技术&#xff0c;它能够提高图像的对比度而又避免过度增强噪声。 在OpenCV中&#xff0c;cv2.createCLAHE() 函数用于创建CLAHE对象&#xff0c;然后可以…

Python 安装win32com失败

今天进行服务器迁移&#xff0c; 中间有用的python调用win32com组件让docx转换成pdf。不出意外的话出意外了&#xff0c;pip安装win32com的时候各种安装不上&#xff0c; 今天处理完问题之后&#xff0c;记录一下&#xff0c;与人方便与己方便。 在cmd上面&#xff0c;一开始…

配置静态 Eth-trunk

1、需求 1&#xff09;交换网络中存在2个 VLAN – 10 和 20 2&#xff09;每个VLAN的IP地址为&#xff1a;192.168.xx.0/24&#xff08;xx为 vlan 号&#xff09; 3&#xff09;对交换机之间的链路进行链路捆绑&#xff0c;增加互联带宽 4&#xff09;确保同 VLAN的 PC 之间互…

static和extern

1.extern extern 是⽤来声明外部符号的&#xff0c;如果⼀个全局的符号在A⽂件中定义的&#xff0c;在B⽂件中想使⽤&#xff0c;就可以使⽤ extern 进⾏声明&#xff0c;然后使⽤。 即在一个源文件中想要使用另一个源文件&#xff0c;即可通过这个extern来声明使用。 2.st…