B-树和B+树

B-树读作B树, 中间的’-'不是减号.

MySQL数据库的索引的数据结构主要是Hash表或B+树.

先引入问题, 数据库索引为什么使用树结构存储?
因为树的查询效率高, 而且可以保持有序. 二叉树的时间复杂度是O(logN), 查找和比较次数都是最小的, 但是并没有使用二叉树作为索引的数据结构.

没有使用二叉树的原因是因为磁盘IO, 数据库引擎是存储在磁盘上的, 当数据量比较大的时候, 索引的大小可能有几个G甚至更多. 当我们利用索引查询的时候, 不可能将整个索引全部加载到内存中去, 只能逐一加载每一个磁盘页, 这里的磁盘页对应的索引树的节点.
在这里插入图片描述
如果使用二叉树作为索引结构, 那么磁盘IO的数次就会非常频繁, 如果二叉树的高很大, 最坏情况下, 磁盘IO次数就是索引树的高度.

所以, 为了减少磁盘IO次数, 就需要把原本"瘦高"的树结构变得"矮胖". 这就是B-树的特征之一.

B树是一种多路平衡查找树, 它的每一个节点最多包含k个孩子, k被称为B树的阶. k的大小取决于磁盘页的大小.

B-树

下面来具体介绍一下B-树(Balance Tree),一个m阶的B树具有如下几个特征:

  1. 根节点至少有两个子女.
  2. 每个中间节点都包含k-1个元素和k个孩子, 其中m/2 <= k <= m
  3. 每一个叶子节点都包含k-1个元素, 其中m/2 <= k <= m
  4. 所有的叶子节点都位于同一层
  5. 每个节点中的元素从小到大排列, 节点当中k-1个元素正好是k个孩子包含的元素的值域划分.

在这里插入图片描述
上图是一个三阶B-树
重点分析(2, 6)节点, 该节点有两个元素2和6, 又有三个孩子(1), (3, 5), (8). 其中1小于元素2, 元素3和5正好在元素2和6之间, 8大于元素2, 6, 正好符合刚才所列的特征.
在这里插入图片描述
假定要查找5, 第一次磁盘IO在9, 第二次磁盘IO读到(2, 6), 第三次磁盘IO读到(3, 5),找到5. 整个流程下来, B-树在查询中的比较次数其实不比二叉查找数少, 尤其当单一节点中的元素数量很多时.

可是相比磁盘IO的速度, 内存中的比较耗时几乎可以忽略. 所有只要树的高度足够低, IO次数足够少, 就可以提升查找性能.

向相比之下节点内容元素多一些也没有关系, 仅仅是多了几次内存交互, 只要不超过磁盘页的大小即可. 这就是B-树的优势之一.

B-树的插入和删除

B-树插入新节点的过程比较复杂, 而且分成很多种情况. 这里举例最典型的例子, 加入我们要插入的值4.
自顶向下查找4的节点位置, 发现4应当插入到节点元素3和5之间.
节点3, 5已经是两元素节点, 无法再增加. 父亲节点2, 6也是两元素节点, 也无法再增加. 根节点9是单元素节点, 可以升级为两元素节点. 于是拆分节点3, 5与节点2, 6, 让根节点9升级为两元素节点4, 9. 节点6独立为根节点的第二个孩子.在这里插入图片描述
插入一个元素后, 让整个B树的这么多子节点都发生了连锁改变. 看起来会很麻烦, 但也正因为如此, 让B-树能够始终维持多路平衡. 这也是B-树的一大优势: 自平衡.

现在来删除元素11:
自顶向下查找元素11的节点位置.
在这里插入图片描述
删除节点11后, 节点12只有一个孩子, 不符合B树规范. 因此找出12, 13, 15三个节点的中位数13, 取代节点12, 而节点12自身下移成为第一个孩子(这个过程成为左旋)
在这里插入图片描述

B-树的应用

B-树主要应用于文件系统以及部分数据库引擎索引, 比如非关系型数据库MongoDB.
而大部分关系型数据库, 比如MySQL, 则使用B+树作为索引.

B+树

B+树是基于B-树的一种变体, 有着比B-树更高的查询性能.

B+树和B-树也有一些共同点, 但是B+树也具备一些新的特征.

一个m阶的B+树具有如下几个特征:

  1. 有k个子树的中间节点包含有k个元素(B树中是k-1个元素), 每个元素不保存数据, 只用来索引, 所有数据都保存在叶子节点.
  2. 所有的叶子节点中包含了全部元素的信息, 及指向含这些元素记录的指针, 且叶子节点本身依关键字的大小自小而大顺序链接.
  3. 所有的中间节点元素都同时存在于子节点, 在子节点元素中是最大(或最小)元素.

举个例子
在这里插入图片描述
在这里插入图片描述
B+树的几个特点. 首先, 每一个父节点的元素都出现在子节点中, 是子节点的最大(或最小)元素.

在上面这棵树中, 根节点元素8是子节点2, 5, 8的最大元素, 也是叶子节点6, 8的最大元素.

根节点元素15是子节点11, 15的最大元素, 也是叶子节点13, 15的最大元素.

至于叶子节点, 由于父节点的元素都出现在子节点, 因此所有叶子节点包含了全量元素信息.

而且每一个叶子节点都带有指向下一个节点的指针, 形成了一个有序链表.
在这里插入图片描述
B+树还具有一个特点, 这个特点是在索引之外, 确实至关重要的特点. 那就是"卫星数据"的位置.

B-树中的卫星数据(Satellite Information):
在这里插入图片描述
而在B+树当中, 只有叶子节点带有卫星数据, 其余中间节点仅仅是索引, 没有任何数据关联.

B+树中的卫星数据(Satellite Information):
在这里插入图片描述
需要补充的是, 在数据库饿聚集索引(Clustered Index)中, 叶子节点直接包含卫星数据. 在非聚集索引(NonClustered Index)中, 叶子节点带有指向卫星数据的指针.

B+树这样设计的好处, 好处主要体现在查询性能上. 下面我们分别来通过单行查询和范围查询来做分析.

在单元素查询的时候, B+树会自顶向下逐层查找节点, 最终找到匹配的叶子节点. 比如要查找元素3;
第一次磁盘IO 根节点;
第二次磁盘IO (2, 5, 8)节点
第三次磁盘IO (3, 5)节点

整个流程和B-树差不多, 但有两点不同. 首先, B+树的中间节点没有卫星数据, 所以同样大小的磁盘页可以容纳更多的节点元素.

这意味着, 数据量相同的情况下, B+树的结构比B-树更加"矮胖", 因此查询时IO次数也更少.

其次, B+树的查询必须最终查找到叶子节点, 而B-树只要找到匹配元素即可, 无论匹配元素处于中间节点还是叶子节点.

因此, B-树的查找性能并不稳定(最好情况是只查根节点, 而最坏情况是查找到叶子节点). 而B+树的每一次查找都是稳定的.

如果是范围查询, B-树只能频繁地使用中序遍历, 查询范围3到11的元素:
B-树需要不断的执行中序遍历.

而B+树只要在链表上做遍历即可.

综合起来, B+树相比B-树的优势有三个: IO次数更少、查询性能稳定、范围查询简便.

B+树的插入和删除,过程与B-树差不多.

总结

B+树的特征:
  1. 有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。

  2. 所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。

  3. 所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。

B+树的优势:
  1. 单一节点存储更多的元素,使得查询的IO次数更少。

  2. 所有查询都要查找到叶子节点,查询性能稳定。

  3. 所有叶子节点形成有序链表,便于范围查询。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值