B+树和B-树

1.简介

B-树概述
B-树,这里的 B 表示 balance( 平衡的意思)

空间局部性原理:如果一个存储器的某个位置被访问,那么将它附近的位置也会被访问。

我们从“迎合”磁盘的角度来看看B-树的设计。

索引的效率依赖与磁盘 IO 的次数,快速索引需要有效的减少磁盘 IO 次数,如何快速索引呢?索引的原理其实是不断的缩小查找范围,就如我们平时用字典查单词一样,先找首字母缩小范围,再第二个字母等等。平衡二叉树是每次将范围分割为两个区间。为了更快,B-树每次将范围分割为多个区间,区间越多,定位数据越快越精确。那么如果节点为区间范围,每个节点就较大了。所以新建节点时,直接申请页大小的空间(磁盘存储单位是按 block 分的,一般为 512 Byte。磁盘 IO 一次读取若干个 block,我们称为一页,具体大小和操作系统有关,一般为 4 k,8 k或 16 k),计算机内存分配是按页对齐的,这样就实现了一个节点只需要一次 IO。

B树和B-tree理解成了两种不同类别的树,其实这两个是同一种树;

B+树概念
B+树是B树的一个升级版,相对于B树来说B+树更充分的利用了节点的空间,让查询速度更加稳定,其速度完全接近于二分法查找。为什么说B+树查找的效率要比B树更高、更稳定;我们先看看两者的区别

2.规则

2.1B树规则

(1)排序方式:所有节点关键字是按递增次序排列,并遵循左小右大原则;
(2)子节点数:非叶节点的子节点数>1,且<=M ,且M>=2,空树除外(注:M阶代表一个树节点最多有多少个查找路径,M=M路,当M=2则是2叉树,M=3则是3叉);
(3)关键字数:枝节点的关键字数量大于等于ceil(m/2)-1个且小于等于M-1个(注:ceil()是个朝正无穷方向取整的函数 如ceil(1.1)结果为2);
(4)所有叶子节点均在同一层、叶子节点除了包含了关键字和关键字记录的指针外也有指向其子节点的指针只不过其指针地址都为null对应下图最后一层节点的空格子;

2.2B+树规则

(1)B+跟B树不同B+树的非叶子节点不保存关键字记录的指针,只进行数据索引,这样使得B+树每个非叶子节点所能保存的关键字大大增加;
(2)B+树叶子节点保存了父节点的所有关键字记录的指针,所有数据地址必须要到叶子节点才能获取到。所以每次数据查询的次数都一样;
(3)B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针。
(4)非叶子节点的子节点数=关键字数(来源百度百科)(根据各种资料 这里有两种算法的实现方式,另一种为非叶节点的关键字数=子节点数-1(来源维基百科),虽然他们数据排列结构不一样,但其原理还是一样的Mysql 的B+树是用第一种方式实现);

3.了解B+树

B+树和B-树_第1张图片

  • 从上图可以看出,不但节点之间含有重复元素,而且叶子结点还用指针连接在一起。这正是B+数的几个特征,首先,每个元素都出现子节点中,是子节点的最大(或者最小)元素。

  • 在上面这课树中,根节点元素8是子节点2,5,8的最大元素,也是叶子节点6,8的最大元素。需要注意的是根节点的最大元素(这里是15),也就等同于整个B+树的最大元素。以后无论插入删除多少元素,始终保持最大元素在根节点当中。

  • 至于叶子节点,由于父节点的元素都出现在子节点,因此叶子结点包含了全部元素的信息。并且每个叶子节点都带有指向下一个节点的指针,形成了一个有序链表。

B+树还具有一个重要的特点,这个特点是在索引之外,确实至关重要的特点。那就是【卫星数据】,

所谓卫星数据,指的就是索引元素所指向的数据记录,比如数据库中的某一行。在B-树中,无论是中间节点还是叶子结点都带有卫星数据,而在B+树当中,只有叶子节点带有卫星数据,其余中间节点仅仅是索引,没有任何数据关联。

B-树中的卫星数据(Satellite Information):
B+树和B-树_第2张图片
B+树中的卫星数据(Satellite Information):
B+树和B-树_第3张图片
需要补充的是,在数据库的聚集索引(Clustered Index)中,叶子节点直接包含卫星数据。在非聚集索引(NonClustered Index)中,叶子节点带有指向卫星数据的指针。

4.区别特点

1、B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;

2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;

3、B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。
4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。

B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。

前面说过B+树是多路查找树,子节点的个数可以是2到无限个,那么问题来了,是不是B+树的子节点个数越多越好呢?

其实不然,如果是极端情况子节点个数就等于总个数,那么B+树退化成了线性表数组,检索效率大大下降,这种情况肯定是不行的,其实思考这个问题也很容易,我们想一下B树出现的初衷是为了解决磁盘系统的高效率的检索,树的高度自然是越低越好,但也不意味着子节点的个数应该尽可能的多,B树的设计要充分考虑磁盘的读写和缓冲机制,前面的文章说过,磁盘块和页内存一般都是4kb,而磁盘有预读机制,每次读的时候都是加载一个磁盘页到内存里面,所以我们的节点数的总大小应该是尽可能的贴近磁盘页的大小,这样以来可以达到最好的读写效率也充分的利用了磁盘cache的预读机制。

扩展:
B* 树规则
B*树是B+树的变种,相对于B+树他们的不同之处如下:
(1)首先是关键字个数限制问题,B+树初始化的关键字初始化个数是cei(m/2),b树的初始化个数为(cei(2/3m))

(2)B+树节点满时就会分裂,而B*树节点满时会检查兄弟节点是否满(因为每个节点都有指向兄弟的指针),如果兄弟节点未满则向兄弟节点转移关键字,如果兄弟节点已满,则从当前节点和兄弟节点各拿出1/3的数据创建一个新的节点出来;

特点
在B+树的基础上因其初始化的容量变大,使得节点空间使用率更高,而又存有兄弟节点的指针,可以向兄弟节点转移关键字的特性使得B*树额分解次数变得更少;

你可能感兴趣的:(b树,数据结构)