本文主要解答索引为什么选择B+Tree,而不使用哈希、二叉搜索树、二叉平衡树、红黑树、B Tree。
索引选择哪种数据结构,主要从两方面来考虑:
本文通过讲解每种数据结构在这两方面的效率,以及其他方面的优缺点,来回答为什么选择B+Tree。
本人还写了MySQL相关博文,有兴趣的研友可以点击如下链接,请各位研友指正并留言。
MySQL事务与隔离级别
MySQL的锁及其MVCC
MySQL索引及优化
哈希数据结构如图所示:
哈希数据结构的哈希值是将键通过某种哈希算法转化而来,哈希算法是多种多样的,也可以自定义的。
优点:只要知道“键”,立马通过哈希算法得到哈希值,从而找到目标数据,查询速度快。
缺点如下:
总结:哈希数据结构存储效率正常,对于定值查询效率高,但不支持范围查询。
树的结构为一个节点可以有多个叶节点。如图所示:
缺点:查询数据时,需要对数一层一层的查找,效率低。
二叉树在树的结构上进行了优化,为了方便管理,规定每个节点最多只能有两个子节点。(这是为了进一步优化为二叉搜索树、二叉平衡树等)
缺点:查询数据时,需要对数一层一层的查找,效率低。
在二叉树的基础上,二叉搜索树作了进一步规定:
优点:根据二叉搜索树规定的节点与左右节点的关系,查询数据时,可使用二分查找,查询效率大大提升。
缺点:存储数据时,如果数据是有序的,并按顺序存储时,会导致某一字数过长,如,顺序存储1、2、3、4、5,如图所示:
由图可见,对于这种特殊插入情况,会导致二叉树搜索树失去树的结构,称为了一种链式结构,那么就会导致查询数据时效率低。
针对二叉搜索树的缺点,二叉平衡树在二叉树的基础上,加入了左右旋,以满足最长子树与最短子树相差不超过1,同时也满足二分查找。
顺序插入1、2、3时,二叉平衡树右旋,如图所示:
顺序插入4、5时,二叉平衡树右旋,最终树如图所示:
优点:查询数据时,可使用二分查找提高查询效率。
缺点:
针对二叉平衡树的左右旋操作,红黑树进行了改进,目的在于,牺牲一点存储效率,以提升查询效率。
红黑树规定:
红黑变色规则:
顺序插入1、2、3、4、5、6时,红黑树如图所示:
优点:相对于二叉平衡树的插入效率要高,因为左右旋的次数降低。
缺点:随着存储数据的增多,树的层次加深,那么访问数据的IO次数也增加,导致查询数据效率逐渐变低。
基于红黑树的缺点,要想降低树的深度,那么要打破每个节点只能存储两个子节点的限制。
允许每个节点有多个子节点,B Tree如图所示:
优点:相对于红黑树,在相同数据量的条件下,B Tree的深度较小。
缺点:
基于B Tree深度还是会加深的缺点,试图让一个节点存储更对的“键”,一个办法就是将节点中的数据data去掉,这样一个节点存储“键”的个数增加,所以深度就会降低。
基于B Tree不能范围查找的缺点,B+Tree在叶子节点中,增加双向链表,就可以进行范围查找。
经过从哈希数据结构到B+Tree数据结构的讲解,理解了每一种树要解决的问题,现在很容易理解索引选择B+Tree的原因了吧。
注意:
InnoDB存储引擎的最小储存单元——页(Page),一个页的大小是16K。假设一行数据的大小是1k,那么一个页可以存放16行这样的数据。
假设主键ID为bigint类型,长度为8字节,而指针大小在InnoDB源码中设置为6字节,这样一共14字节,我们一个页中能存放多少这样的单元,其实就代表有多少指针,即16*1024/14=1170。
可以算出一个高度为3的B+Tree可以存放:1170 * 1170 * 16=21902400条这样的记录。
InnoDB中B+Tree的叶子节点存储了数据,而MyISAM中B+Tree的叶子节点存储了数据的地址。
InnoDB的B+Tree:
MyISAM的B+Tree:
聚集索引:在B+Tree中,叶子节点存储了整行数据的索引。在InnoDB中,只有主键索引是聚集索引,当没有主键时,会选取唯一键;当没有唯一键时,会添加6位row_id作为主键。其他索引都是非聚集索引。
非聚集索引:在B+Tree中,叶子节点没有存储整行数据的索引。比如MyISAM中B+Tree叶子节点存储的是数据的地址。
在InnoDB中,除主键索引外,比如组合索引,叶子节点存储的是数据的主键信息。当通过组合索引查询到对应的主键信息后,再到主键索引中查询整行数据,该过程称为回表。
在InnoDB中,使用索引查询到对应数据的主键信息,该主键正是本次查询的数据,可以直接返回,而不用访问回表,该过程称为覆盖索引。
当有组合索引name、age时,通过该索引查询会先根据name得到主键并回表,回表会增加查询的步骤、降低查询效率,回到主键索引再查询age。
而使用索引下推后,就会优先在索引上进行查询过滤。
使用explain查询会发现: