联合索引在B+树上的存储结构及数据查找方式

能坚持别人不能坚持的,才能拥有别人不曾拥有的。
关注 编程大道公众号,让咱们一同坚持心中所想,一块儿成长!!

引言

上一篇文章《MySQL索引那些事》主要讲了MySQL索引的底层原理,且对比了B+Tree做为索引底层数据结构相对于其余数据结构(二叉树、红黑树、B树)的优点,最后还经过图示的方式描述了索引的存储结构。但都是基于单值索引,因为文章篇幅缘由也只是在文末略提了一下联合索引,并无大篇幅的展开讨论,因此这篇文章就单独去讲一下联合索引在B+树上的存储结构。
本文主要讲解的内容有:数据库

  • 联合索引在B+树上的存储结构
  • 联合索引的查找方式
  • 为何会有最左前缀匹配原则


在分享这篇文章以前,我在网上查了关于MySQL联合索引在B+树上的存储结构这个问题,翻阅了不少博客和技术文章,其中有几篇讲述的与事实相悖。庆幸的是看到搜索引擎列出的有一条是来自思否社区的问答,有答主回答了这个问题,贴出一篇文章和一张图以及一句简单的描述。PS:贴出的文章连接已经打不开了。
因此在这样的条件下这篇文章就诞生了。编程

联合索引的存储结构

下面就引用思否社区的这个问答来展开咱们今天要讨论的联合索引的存储结构的问题。
来自思否的提问,联合索引的存储结构(https://segmentfault.com/q/1010000017579884)有码友回答以下:segmentfault


联合索引 bcd , 在索引树中的样子如图 , 在比较的过程当中 ,先判断 b 再判断 c 而后是 d ,


因为回答只有一张图一句话,可能会让你有点看不懂,因此咱们就借助前人的肩膀用这个例子来更加细致的讲探寻一下联合索引在B+树上的存储结构吧。缓存


首先,表T1有字段a,b,c,d,e,其中a是主键,除e为varchar其他为int类型,并建立了一个联合索引idx_t1_bcd(b,c,d),而后b、c、d三列做为联合索引,在B+树上的结构正如上图所示。联合索引的全部索引列都出如今索引数上,并依次比较三列的大小。上图树高只有两层不容易理解,下面是假设的表数据以及我对其联合索引在B+树上的结构图的改进。PS:基于InnoDB存储引擎。
数据结构

                                                                                         bcd联合索引在B+树上的结构图学习

                                    T1表优化


经过这俩图咱们内心对联合索引在B+树上的存储结构就有了个大概的认识。下面用个人语言为你们解释一下吧。搜索引擎


咱们先看T1表,他的主键暂且咱们将它设为整型自增的(PS:至于为何是整型自增上篇文章有详细介绍这里再也不多说),InnoDB会使用主键索引在B+树维护索引和数据文件,而后咱们建立了一个联合索引(b,c,d)也会生成一个索引树,一样是B+树的结构,只不过它的data部分存储的是联合索引所在行的主键值(上图叶子节点紫色背景部分),至于为何辅助索引data部分存储主键值上篇文章也有介绍,感兴趣或还不知道的能够去看一下。spa

好了大体状况都介绍完了。下面咱们结合这俩图来解释一下。3d


对于联合索引来讲只不过比单值索引多了几列,而这些索引列全都出如今索引树上。对于联合索引,存储引擎会首先根据第一个索引列排序,如上图咱们能够单看第一个索引列,如,1 1 5 12 13....他是单调递增的;若是第一列相等则再根据第二列排序,依次类推就构成了上图的索引树,上图中的1 1 4 ,1 1 5以及13 12 4,13 16 1,13 16 5就能够说明这种状况。

联合索引的查找方式

当咱们的SQL语言能够应用到索引的时候,好比 select * from T1 where b = 12 and c = 14 and d = 3; 也就是T1表中a列为4的这条记录。存储引擎首先从根节点(通常常驻内存)开始查找,第一个索引的第一个索引列为1,12大于1,第二个索引的第一个索引列为56,12小于56,因而从这俩索引的中间读到下一个节点的磁盘文件地址,从磁盘上Load这个节点,一般伴随一次磁盘IO,而后在内存里去查找。当Load叶子节点的第二个节点时又是一次磁盘IO,比较第一个元素,b=12,c=14,d=3彻底符合,因而找到该索引下的data元素即ID值,再从主键索引树上找到最终数据。

最左前缀匹配原则

之因此会有最左前缀匹配原则和联合索引的索引构建方式及存储结构是有关系的。
首先咱们建立的idx_t1_bcd(b,c,d)索引,至关于建立了(b)、(b、c)(b、c、d)三个索引,看完下面你就知道为何至关于建立了三个索引。
咱们看,联合索引是首先使用多列索引的第一列构建的索引树,用上面idx_t1_bcd(b,c,d)的例子就是优先使用b列构建,当b列值相等时再以c列排序,若c列的值也相等则以d列排序。咱们能够取出索引树的叶子节点看一下。
索引的第一列也就是b列能够说是从左到右单调递增的,但咱们看c列和d列并无这个特性,它们只能在b列值相等的状况下这个小范围内递增,如第一叶子节点的第一、2个元素和第二个叶子节点的后三个元素。
因为联合索引是上述那样的索引构建方式及存储结构,因此联合索引只能从多列索引的第一列开始查找。因此若是你的查找条件不包含b列如(c,d)、(c)、(d)是没法应用缓存的,以及跨列也是没法彻底用到索引如(b,d),只会用到b列索引。
这就像咱们的电话本同样,有名和姓以及电话,名和姓就是联合索引。在姓能够以姓的首字母排序,姓的首字母相同的状况下,再以名的首字母排序。

如:

M    

  毛 不易   178********   

  马 化腾   183********   

  马 云       188********

Z   

  张 杰      189********   

  张 靓颖   138********   

  张 艺兴   176********  

咱们知道名和姓是很快就可以从姓的首字母索引定位到姓,而后定位到名,进而找到电话号码,由于全部的姓从上到下按照既定的规则(首字母排序)是有序的,而名是在姓的首字母必定的条件下也是按照名的首字母排序的,可是总体来看,全部的名放在一块儿是无序的,因此若是只知道名查找起来就比较慢,由于没法用已排好的结构快速查找。

到这里你们是否明白了为啥会有最左前缀匹配原则了吧。

实践

以下列举一些SQL的索引使用状况

 1 select * from T1 where b = 12 and c = 14 and d = 3;-- 全值索引匹配 三列都用到
 2 
 3 select * from T1 where b = 12 and c = 14 and e = 'xml';-- 应用到两列索引
 4 
 5 select * from T1 where b = 12 and e = 'xml';-- 应用到一列索引
 6 
 7 select * from T1 where b = 12  and c >= 14 and e = 'xml';-- 应用到一列索引及索引条件下推优化
 8 
 9 select * from T1 where b = 12  and d = 3;-- 应用到一列索引  由于不能跨列使用索引 没有c列 连不上
10 
11 select * from T1 where c = 14  and d = 3;-- 没法应用索引,违背最左匹配原则

后记

到这里MySQL索引的联合索引的存储结构及查找方式就讲完了,本人能力有限,也是站着前人的肩膀上创做的此文,由于看到搜索引擎的搜索结果前几个技术文章中有存在讲述不清或讲述有误的地方,因此本身才总结出这篇文章分享给你们,若有不对的地方必定要指正哦,谢谢了。


这篇文章断断续续利用工做之余画图加写做用了两三天,主要内容就是上面这些了。不能否认,这篇文章在必定程度上有纸上谈兵之嫌,由于我本人对MySQL的使用属于菜鸟级别,更没有太多数据库调优的经验,在这里高谈阔论实属惭愧。就当是我我的的一篇学习笔记了。


另外,MySQL索引及知识很是普遍,本文只是涉及到其中一部分。如与排序(ORDER BY)相关的索引优化及覆盖索引(Covering index)的话题本文并未涉及,同时除B-Tree索引外MySQL还根据不一样引擎支持的哈希索引、全文索引等等本文也并未涉及。若是有机会,但愿再对本文未涉及的部分进行补充吧。
创做不易,若是对你有帮助,请不要吝啬你的赞,这对我是很大的鼓励~

 


~~手机阅读的用户请扫码关注公众号,你的关注是对我最大的支持!~~

 

 

 

 


以为好看,请点这里

相关文章
相关标签/搜索