为何MySQL使用B+而不是使用B树、二叉树、AVL树呢?(前因后果的去理解)

当你回答使用B+ 怎么怎么好的时候,其实这道面试题你就注定答不满分了,你应该是从一步步若是演变到使用B+来作MySQL的数据结构,下面就一步一步从二叉树——>AVL(平衡二叉树)——>B Tree(多路平衡查找树)——>B+ Tree的一个演变的过程来进行分析,为何使用B+ Tree的?

(1)先从二叉树开始提及:html

  • 首先你得知道二叉树是什么吧:看下面的图一你就该很熟悉了吧
  • 而后你得知道二叉树查询的时间复杂度是O(log2(n)),这样感受其实二叉树的查询效率挺高的,可是他会出现另外一种现象,就是下面的图二:
  • 这样就致使了二叉树的查询效率不问题,若是运气好的话查询效率就很高,若是运气很差的话,就会出现图二的状况,所以在二叉树的基础上又进行的改进,演变出来了平衡二叉树(AVL树)

图一:
在这里插入图片描述
图二:
在这里插入图片描述node

(2)而后到了平衡二叉树(AVL树):mysql

  1. 首先你得知道平衡二叉树的定义吧:在知足二叉树的基础上,任意两个节点的两个子树的高度差不能超过1:就比如下面的这个图的一个效率不好的二叉树,好比5节点的左子树的高度是0,右字树的高度是2,,因此很明显不知足平衡二叉树的概念
    在这里插入图片描述
  2. AVL树主要是为了解决上面的图出现的状况,因此如今要把上图的二叉树转插入一个“9”节点而后换为一个平衡二叉树的状况就是下面的:
    在这里插入图片描述
  3. 能够看出平衡二叉树的缺点就是:(1)维护平衡过程的成本代价很高,由于每次删除一个节点或者增长一个节点的话,须要一次或者屡次的左旋,右旋等去维护“平衡”状态(2)而后是查询的效率不稳定,仍是会有看运气的成分在里面(3)而后是若是节点不少的话,那么这个AVL树的高度仍是会很高的,那么查询效率仍是会很低,
  4. 还有就是节点存储的数据内容太少。没有很好利用操做系统和磁盘数据交换特性,也没有利用好磁盘IO的预读能力。由于操做系统和磁盘之间一次数据交换是已页为单位的,一页 = 4K,即每次IO操做系统会将4K数据加载进内存。可是,在二叉树每一个节点的结构只保存一个关键字,一个数据区,两个子节点的引用,并不可以填满4K的内容。幸幸苦苦作了一次的IO操做,却只加载了一个关键字,在树的高度很高,刚好又搜索的关键字位于叶子节点或者支节点的时候,取一个关键字要作不少次的IO。所以平衡二叉树也是不太符合MySQL的查询结构的。

(3)而后到了使用B Tree(多路平衡查找树)web

  1. 首先你也得知道B Tree的基本概念:全部的叶子节点的高度都是同样,这个保证了每次查询数据的时候都是稳定的查询效率,不会由于运气的影响
  2. 而后B Tree中其实每一个非叶子节点内的小节点内其实都是一个二元组[key, data],key其实就是下图的那个25这种的,而后这个data其实对应的就是数据库中id等于25这条完整的数据记录的内存地址(由于在Myisam中他是数据和索引数据是分开的)

在这里插入图片描述
B树的特色:面试

  1. 首先B Tree的每个节点上实际上是有date的,这个date其实就是
  2. 而后是B Tree查询的效率不够稳定,他有可能在第一个节点中就查到了数据,而且返回
  3. 他的键值其实都是分布在整棵树上的节点上的任何一个节点

(4)而后到了使用B+ Tree(多路平衡查找树)sql

  1. 首先你要知道什么B+ Tree,其实他是专门为磁盘或者其余的直接存取辅助设备设计的一种平衡查找树,在B树中,全部的节点都是按照键值的大小顺序存放在同一层的叶子节点上,由各叶子节点的指针链接。数据库

  2. 下图的一颗B树,是一个高度为2,每一页能够放4条记录,扇出是5。
    在这里插入图片描述
    重要的第一点:数据结构

  3. 重要的第一点:B+ Tree有一个很大的改变就是他的每个非叶子节点的内节点中都没有date这个概念了,都变成了key,由于他的date都放在了叶子节点上,这样的一个最大的好处就利用了局部性原理(当一个数据被用到时,其附近的数据也一般会立刻被使用)与磁盘预读的特性(磁盘每每不是严格按需读取,而是每次都会预读,即便只须要一个字节,磁盘也会从这个位置开始,顺序向后读取必定长度的数据【这个必定的长度就是一个节点的大小设置为16K】放入内存)svg

  4. 接着上面的:预读的长度通常为页(page)的整倍数。页是计算机管理存储器的逻辑块,硬件及操做系统每每将主存和磁盘存储区分割为连续的大小相等的块,每一个存储块称为一页(在许多操做系统中,页得大小一般为4k),主存和磁盘以页为单位交换数据。当程序要读取的数据不在主存中时,会触发一个缺页异常,此时系统会向磁盘发出读盘信号,磁盘会找到数据的起始位置并向后连续读取一页或几页载入内存中,而后异常返回,程序继续运行。操作系统

  5. 重要的第二点:因为上面咱们说的预读原理,由于B+ Tree中节点的内节点无 data 域,其实就是由于没有date域了,可是每次IO的页的大小是固定的,可是B+Tree中没有了date域,那么确定每次IO读取若干个块块中包含的Key域的值确定更多啊,B+树单次磁盘 IO 的信息量大于B树,从这点来看B+树相对B树磁盘 IO 次数少。

  6. 数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每一个节点只须要一次I/O就能够彻底载入。

  7. 为了达到这个目的在实际实现B-Tree还须要使用以下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。

重要的第二点:

  1. B+Tree中由于数据都在叶子节点,因此每次查询的时间复杂度是固定的,由于稳定性保证了
  2. 并且叶子节点之间都是链表的结构,因此B+ Tree也是能够支持范围查询的,而B树每一个节点 key 和 data 在一块儿,则没法区间查找。

参考索引:http://blog.codinglabs.org/articles/theory-of-mysql-index.html
局部性原理文章: https://blog.csdn.net/wwh578867817/article/details/50493940

到了这里相必你已经完全知道了为何使用B+ Tree来做为MySQL索引的数据结构了吧