快彩网

让建站和SEO变得简单

让不懂建站的用户快速建站,让会建站的提高建站效率!

MySQL自增主键为何不是剖析的呢?

发布日期:2022-03-13 21:11    点击次数:60

公共好,我是小龙。之前阿里二面问过我这么一个问题:

口试官:"MySQL主键你一般如何用?"

心想:"嘿嘿,口试官细目想问InnoDB引擎索引特点关联学问!“

小龙:”日常主键我一般用自增主键!因为自增ID有序,会按法规往临了插入,而UUID无序,未必生成,未必插入,会形成常常页分裂,内存碎屑化,大量未必IO,巴拉巴拉。。。。“

心想:“这波稳啦!“

然后,口试官又来一套组合拳

口试官:”en!好,那你清澈自增主键是否严格递加呢?“

心想:”这还不简便,细目递加啊!辞别,仔细一想,有一些情况下自增主键是断开的,于是“

小龙:“‘细目不是递加的啊!"

认为到这里限定啦,仅仅考考我是否实质实在用过,没猜测如故活泼啦!

口试官:”那你清澈为啥不是严格递加的吗?换句话来说,为何不是剖析的?“

小龙:”裂开!tm还真不清澈,不会真要考那么底层吧!我去“

于是骂骂咧咧限定了这个话题!

可是由于其他问题回应的也不错,如故过啦!

不外,既然遭遇啦这个问题,下来查阅了贵寓,如故想共享给公共!

1、前文

人所共知,由于自增主键不错让主键索引尽量地保持递加法规插入,幸免了页分裂,大量的未必IO。自增主键不剖析。

这是公共还是熟知的学问点,可是,可能也有大部分知友和之前的小龙一样不清澈为何自增主键不是严格递加的?

今天这篇著作,咱们就来说说这个问题,望望什么情况下自增主键会出现 “断层”?

为了愈加形象,这里创建一个表xl_tb,其中id是自增主键字段、a是惟一索引,然后插入一条数据,咱们再检察它的表结构。

CREATE TABLE `NewTable` ( `id`  int(11) NOT NULL AUTO_INCREMENT , `a`  int(11) NULL , `b`  int(11) NULL , PRIMARY KEY (`id`), UNIQUE INDEX `a` (`a`) USING BTREE  ); 
insert into xl_tb values(null, 1, 1) 
mysql> show create table xl_tb\G; *************************** 1. row ***************************        Table: xl_tb Create Table: CREATE TABLE `xl_tb` (   `id` int(11) NOT NULL AUTO_INCREMENT,   `a` int(11) DEFAULT NULL,   `b` int(11) DEFAULT NULL,   PRIMARY KEY (`id`),   UNIQUE KEY `a` (`a`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 1 row in set (0.04 sec) 

不错看到,表界说内部出现了一个AUTO_INCREMENT=4,示意下一次插入数据时,如若需要自动生成自升值,会生成id=4。

公共也不错我方手动试试!

可是,看到这里,可能有知友认为自升值存在表结构里吧!哈哈,你这么想就有错啦!

2、自增主键为何不剖析 2.1、自增主键存储政策接下来,咱们一道望望自升值保存在那里吧!

其实,不同的存储引擎,自升值保存政策不一样的。

MyISAM引擎的自升值保存在数据文献中。 InnoDB引擎的自升值,其实是保存在了内存里,而况到了MySQL 8.0版块后,才有了“自升值永远化”的才能,也等于才罢了了“如若发生重启,表的自升值不错复原为MySQL重启前的值”,具体情况是: 在MySQL 5.7及之前的版块,自升值保存在内存里,并莫得永远化。每次重启后,第一次翻开表的时期,都会去找自升值的最大值max(id),然后将max(id)+1算作这个阐扬时的自升值。 例如来说,如若一个阐扬时数据行里最大的id是10,AUTO_INCREMENT=11。这时期,咱们删除id=10的行,AUTO_INCREMENT如故11。但如若立时重启实例,重启后这个表的AUTO_INCREMENT就会变成10。? 也等于说,MySQL重启可能会修改一个表的AUTO_INCREMENT的值。 在MySQL 8.0版块,将自升值的变更纪录在了redo log中,重启的时期依靠redo log复原重启之前的值。

相识了MySQL对自升值的保存政策以后,咱们再望望自升值修改机制。

2.2、自升值修改机制

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

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

2.3、自升值新增机制

如若准备插入的值>=现时自升值,新的自升值等于“准备插入的值+1”;

不然,自升值不变。

2.4、自升值的修改时机

eg:

假定,表xl_tb内部还是有了(1,1,1)这笔纪录,这时我再施行一条插入数据呐喊:

insert into t values(null, 1, 1); (自增id,惟一键a,粗俗字段b) 

这个语句的施行历程等于:

施行器调用InnoDB引擎接口写入一瞥,传入的这一瞥的值是(0,1,1); InnoDB发现用户莫得指定自增id的值,赢得表xl_tb现时的自升值4; 将传入的行的值改成(2,1,1); 将表的自升值改成5; 络续施行插入数据操作,由于还是存在a=1的纪录,是以报Duplicate key error,语句复返。

这个表的自升值改成5,是在实在施行插入数据的操作之前。这个语句实在施行的时期,因为碰到惟一键a突破,是以id=2这一瞥并莫得插入告捷,但也莫得将自升值再改且归。

是以,在这之后,再插入新的数据行时,拿到的自增id等于5。也等于说,出现了自增主键不剖析的情况。因此,惟一键突破是导致自增主键id不剖析的第一种原因。

相同地,事务回滚也会产生访佛的风景,这等于第二种原因。

这时,你可能会想,为什么在出现惟一键突破大致回滚的时期,MySQL莫得把表xl_tb的自升值改且归呢?如若把表xl_tb确现时自升值从5改回4,再插入新数据的时期,不就不错生成id=2的一瞥数据了吗?

那么,接下来随着我的思绪来望望,为何不让自增主键后退吧!

率先,咱们假定有两个并行施行的事务A、B,在苦求自升值的时期,为了幸免两个事务苦求到交流的自增id,细目要加锁,然后法规苦求。

率先,事务A苦求到 id=2,此时现时自升值为3,由于加锁法规苦求,事务B苦求到 id=3(现时自升值),此时,现时自升值变为 3+1=4 然后,事务 A、B都插入,假定事务B先插入然后告捷插入,然后事务A插入发生了惟一键突破 如若假定允许自升值后退,自升值就变为2啦,假如事务A络续插入,苦求到 id=2,告捷插入,苦求到 id=3,插入,由于之前事务B还是插入 id=3的数据,此时发生主键突破

那如何科罚呢?

每次苦求id之前,先判断表内部是否还是存在这个id。 扩大锁限制,必须等事务施行完,才能苦求下一个

固然这两种法度不错科罚,可是无疑性能极低。

于是,便让自升值不行回退,而幸免形成主键突破等问题。(也许还有其他问题我莫得猜测)

3、回来

为什么自增主键不剖析?

在MySQL 5.7及之前的版块,自升值保存在内存里,并莫得永远化

事务回滚(自升值不行回退,因为并发插入数据时,回退自增ID可能形成主键突破)

惟一键突破(由于表的自升值已变,可是主键发生突破没插进去,下一次插入主键=目下变了的子升值+1,是以不剖析) 

好啦,今天的共享到此限定啦!有疑问宽待后台留言,大致加入工夫交流群公共一道征询学习!

本文转载自微信公众号「小龙coding」,不错通过以下二维码心绪。转载本文请关联小龙coding公众号。

 



栏目分类



Powered by 快彩网 @2013-2022 RSS地图 HTML地图

Copyright 站群 © 2013-2021 365建站器 版权所有