提到惟一索引和普通索引,置信大家都不生疏,当共事**姐问你这俩有什么区别时?或许你会信口开河:“这还用问?见名知意啊,一个是准许字段重复,一个不准许存在反双数据!”
能否处置**姐的不懂我不知道,但你在共事心目中,必需不是啥好玩意儿~ 要知道,一眼就看出的答案,普通不会有人问,除非问傻子~
那么当你处置一张市民消息表时,其中一列为市民的身份证号消息,你会怎样选用哪个索引?为什么?
关于一个阅历过风风雨雨、日日夜夜的程序员来说,须要你思考的物品可不只是重不重复这类疑问,而是...
开个玩笑~~应当联合实践状况,对各个场景启动综合思考。
其实,假设在业务代码中保障了不会写入重复的身份证号,那么这两个选用逻辑上都是正确的。但是在SELECT和DML场景中,惟一索引和普通索引却有很多不同。
1、在SELECT中,惟一索引和普通索引的区别
本文测试引擎选用我们最罕用的InnoDB,版本为MySQL8.0;
假定,口头查问的语句是:
(身份证太长,我们用便捷数据做演示)我们知道,MySQL的InnoDB驳回的是B+树成功的索引结构,查找环节从B+树的树根起,按层搜查到666所在的叶子节点,而后取出该节点所在的数据页,把数据页读到内存后,经过二分法在数据页中定位id_card=666的行数据。
B+ 树的查找环节如上图:
1.将磁盘块1从磁盘加载到内存,出现一次性IO ,在内存中经常使用二分查找方式找到 666 在600和700 之间,锁定磁盘块1的P2 指针。
2.经过磁盘块1 的 P2 指针地址把磁盘块3 加载到内存,出现第二次IO ,锁定磁盘块3 的 P2 指针
3.经过磁盘块3 的P2指针加载磁盘块7到内存,出现第三次 IO,同时依据二分查找找到666 查问完结。
普通索引和惟一索引的定位方式:
两者在查问方面的性能差距微不足道。关于普通索引多的那一次性操作,由于自身就是以数据页为单位读进内存,数据页大小自动16KB(大略1000行),要多做的那一次性“查找和判别下一条记载”的操作,就只有要一次性指针寻觅和一次性计算。当然,无法防止查问的数据是该数据页的最后一位,这样还要再读下一块数据页,算法会复杂一些。
但你知道的,这种概率很小,我们程序员要置信逆墨菲定律:大略率不会出现且未被发现的BUG,在难以改变的前提下,你就当不知道就完了,出现了又能咋地?有测试顶着呢!
??有同窗识我了:普通索引为什么要继续向下查找?继续向下查找的要素是由于普通索引准许重复值,且B+Tree是自然有序的。SQL中并没有指定limit1,所以他还要往下查,看能否有同条件的数据一同前往,直到查到第一条不满足条件的数据为止。
2、在DML中,惟一索引和普通索引的区别
ding!这是本篇文章的重点,在看之前,我们须要先了解什么是change buffer。
了解MySQL机制的同窗们知道,当口头 DML(INSERT、UPDATE、DELETE)等操作时,InnoDB会应用 changebuffer启动减速写操作,可以将写操作的随机磁盘访问调整为部分顺序操作,而在机械硬盘时代,随机磁盘访问(随机I/O)也是数据库操作中的最耗性能的硬伤。当普通索引(非惟一索引)的数据页出现写操作时,把操作内容写到内存中的changebuffer后就可以立刻前往(口头成功)了。
这里我以UPDATE操作为例,当须要更新某一行数据时,会先判别该行所在数据页能否在内存中,假设在就间接在内存数据页中更新,假设这个数据页没有内存中的话,在不影响数据分歧性的前提下,InnoDB会将这些UPDATE操作缓存在 change buffer中,这样就不须要从磁盘读入数据页,当有SQL查问须要访问这个数据页的数据时,将数据页读入内存后,而后先口头 change buffer中与这个页的相关UPDATE操作,经过这种方式保障这个数据页的逻辑正确性。
可见,change buffer是会被从内存耐久化到磁盘中的,将 change buffer 中的操作运行到原数据页,获取最新结果的环节被称为merge。除了访问这个数据页会触发 merge 外,系统有后盾线程会活期 merge。在数据库反常封锁(shutdown)的环节中,也会口头 merge操作,相当于刷脏页啦(把已修正的数据更新到实践数据文件中)。
触发merge的操作关键有以下几种(**你该记住的点**):
小好友,你能否有很多问号??DB主机宕机,数据不是就丢了?这就得redo log + binlog来保障了,可以参考作者另一篇文章《听我讲完redolog、binlog原理,面试官老脸一红》[1],本篇不再赘述。
跑远了?言归正传上文提到普通索引(非惟一索引)会经常使用到Change buffer启动减速写操作,痴呆的你是不是曾经get到点了呢?
是的,惟一索引不会经常使用 Change buffer ,假设索引设置了惟一属性,在启动拔出或许修正操作时,InnoDB必需启动惟一性审核,假设不读取索引页到缓冲池,无法校验索引能否惟一,假设都把索引页读到内存了,那间接更新内存会更快,就没必要经常使用changebuffer了。
关于普通索引(非惟一索引)的DML操作来说,当待更新的数据页在内存中时,找到前值和后值的区间拔出即可;当待更新的数据页在不在内存中时,间接把操作写到Changebuffer就完事儿了。舒适!
到这里,置信你对普通索引和惟一索引的取舍有了必定的概念,普通索引和惟一索引在查问才干上是没差异的,关键思考的是更新的影响。还得联合实践业务场景来判别,假设是读取远大于更新和拔出的表,惟一索引和普通索引都可以,但是假设业务需求同样,团体感觉应该经常使用普通索引,当然假设是那种更新完要求立刻可见的需求,就是刚更新完就要再查问的,这种状况下反而不介绍普通索引,由于这样会频繁的发生merge操作,起不到changebuffer的作用,反而须要额外空间来保养change buffer就有点得失相当了。
当我们经常使用普通索引,尤其在经常使用机械盘的场景下,尽量把change buffer开大从而确保数据的写入速度。最后,经过罗列一下 changebuffer 的性能,完结当天的分享,置信看到这里的都是有心人,也是喜欢MySQL的崽子,记得不要悭吝你的点赞哦~~
change buffer 性能
References
[1] 《听我讲完redo log、binlog原理,面试官老脸一红》: