为什么MySQL使用B+而不是使用B树、二叉树、AVL树呢?

为什么MySQL使用B+而不是使用B树、二叉树、AVL树呢?

本文转载自:https://blog.csdn.net/qq_36520235/article/details/94317993,感谢大神!

一、B+树做索引而不用B-树

那么Mysql如何衡量查询效率呢?– 磁盘IO次数。
一般来说索引非常大,尤其是关系性数据库这种数据量大的索引能达到亿级别,所以为了减少内存的占用,索引也会被存储在磁盘上。B-树/B+树 的特点就是每层节点数目非常多,层数很少,目的就是为了减少磁盘IO次数,但是B-树的每个节点都有data域(指针),这无疑增大了节点大小,说白了增加了磁盘IO次数(磁盘IO一次读出的数据量大小是固定的,单个数据变大,每次读出的就少,IO次数增多,一次IO多耗时),而B+树除了叶子节点其它节点并不存储数据,节点小,磁盘IO次数就少。

  • 优点一: B+树只有叶节点存放数据,其余节点用来索引,而B-树是每个索引节点都会有Data域。
  • 优点二: B+树所有的Data域在叶子节点,并且所有叶子节点之间都有一个链指针。 这样遍历叶子节点就能获得全部数据,这样就能进行区间访问啦。在数据库中基于范围的查询是非常频繁的,而B树不支持这样的遍历操作。

二、B+树做索引而不用红黑树

AVL 树(平衡二叉树)和红黑树(二叉查找树)基本都是存储在内存中才会使用的数据结构。在大规模数据存储的时候,红黑树往往出现由于树的深度过大而造成磁盘IO读写过于频繁,进而导致效率低下的情况。为什么会出现这样的情况,我们知道要获取磁盘上数据,必须先通过磁盘移动臂移动到数据所在的柱面,然后找到指定盘面,接着旋转盘面找到数据所在的磁道,最后对数据进行读写。磁盘IO代价主要花费在查找所需的柱面上,树的深度过大会造成磁盘IO频繁读写。根据磁盘查找存取的次数往往由树的高度所决定,所以,只要我们通过某种较好的树结构减少树的结构尽量减少树的高度,B树可以有多个子女,从几十到上千,可以降低树的高度。

数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。为了达到这个目的,在实际实现B-Tree还需要使用如下技巧:每次新建节点时,直接申请一个页的空间,这样就保证一个节点物理上也存储在一个页里,加之计算机存储分配都是按页对齐的,就实现了一个node只需一次I/O。

下面就一步一步从二叉树——>AVL(平衡二叉树)——>B Tree(多路平衡查找树)——>B+ Tree的一个演变的过程来进行分析,为什么使用B+ Tree的?

(1)先从二叉树开始说起:

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

图一:

图二:

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

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(多路平衡查找树)

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

B树的特点:

1.首先B Tree的每一个节点上其实是有date的,这个date其实就是
2.然后是B Tree查询的效率不够稳定,他有可能在第一个节点中就查到了数据,并且返回
3.他的键值其实都是分布在整棵树上的节点上的任何一个节点
(4)然后到了使用B+ Tree(多路平衡查找树)

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

5.下图的一颗B树,是一个高度为2,每一页可以放4条记录,扇出是5。

重要的第一点:

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

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

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

9.数据库系统的设计者巧妙利用了磁盘预读原理,将一个节点的大小设为等于一个页,这样每个节点只需要一次I/O就可以完全载入。

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

重要的第二点:

  1. B+Tree中因为数据都在叶子节点,所以每次查询的时间复杂度是固定的,因为稳定性保证了
  2. 而且叶子节点之间都是链表的结构,所以B+ Tree也是可以支持范围查询的,而B树每个节点 key 和 data 在一起,则无法区间查找。

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值