B-树(Balance树)和B+树应用与数据库索引,是m叉的多路平衡查找树。
1. 性质分析
1.1 M阶B-树
1.1.1 M阶B-树性质
- 每个节点最多包含M个孩子;【M为树的阶,M的大小取决于磁盘页的大小】
- 根节点,至少有2个孩子节点;
- 每个中间节点都包含K-1个关键字和K个孩子,其中关键字以升序排列;【 ceil(M) / 2 <=K<= M】
- 每个叶子节点都包含K-1个元素;【 ceil(M) / 2 <=K<= M】
-
所有叶子节点在同一层;【根节点到每一个叶子节点路径长度相同】
以上图为例查找44:
第一次磁盘IO:在内存中定位与(22,50)比较,22<44<50 ==> P2;
第二次磁盘IO:在内存中定位与(30,42)比较,42<44 ==> P3;
第三次磁盘IO:在内存中定位与(44,50)比较,找到44,终止查找。
1.1.2 B树特性
- 关键字结合分布在整棵树中;
- 任何一个关键字出现且只出现一个节点中;
- 搜索可能在非叶子节点结束;
- 其搜索性能等价于在关键字全集中做一次二分查找。
1.2 M阶B+树
1.2.1 M阶B+树性质
- 有k个子树的中间节点包含k个元素(b-树有k-1个元素),每个元素不保存数据,只保存索引,所有的数据保存在叶子节点中;【 ceil(M) / 2 <=K<= M】
- 所有叶子节点中包含了全部元素的信息,以及指向这些元素的指针,且叶子节点依据关键字的大小自小到大顺序链接;
- 所以中间节点元素都在子节点中存在,在子节点元素中是最大(或最小)元素;
-
在b+树中无论删除插入多少元素,使用要保持最大(最小)元素在根节点中。
以上图为例查找5:
第一次磁盘IO:在内存中定位与(5,28,65)比较,5=5 ==> P1子树;
第二次磁盘IO:在内存中定位与(5,10,20)比较,5=5 ==> P1子树;
第三次磁盘IO:在内存中找到5,终止查找。
1.2.2 B+树特性
- 与B树不同的是,B+树的所有数据都是存在于叶子节点中。在树中去寻找5,需要遍历到叶子节点。
- B+树通常有两个指针,一个指向根结点,另一个指向关键字最小的叶子结点。因些,对于B+树进行查找两种运算:一种是从最小关键字起顺序查找,另一种是从根结点开始,进行随机查找。
2. 相关问题补充
2.1 MySQL的索引使用B+树而不是B树?
- b+树单一节点存储更多的元素,使得IO次数减少【B树不管是叶子节点还是非叶子节点都会存储保存数据信息,这样导致在非叶子中能保存的指针数量变小,指针少的情况下要保存大量数据,就只能增加树的高度,这样在查询操作时效率较低,需要更过磁盘IO次数。在数据量相同的情况下b+树的高度低于b-树高度】
- 所有查询都要查询到叶子节点,查询性能稳定【b+树的查找必须要查找到叶子节点,b-树只要匹配到元素即可,无论匹配元素在中间还是叶子节点。因此相对于b-树的查找,b+树的查找更加稳定】
- 所有叶子节点形成有序链表,便于范围查找【范围查找,b-树只能依靠繁琐的中序遍历,b+树的范围查询只需要在链表上做遍历即可。】
2.2 MySQL中B+树的高度?
在InnoDB中B+树高度一般为1-3层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO,所以通过主键索引查询通常只需要1-3次IO操作即可查找到数据。
https://www.cnblogs.com/leefreeman/p/8315844.html
2.3 InnoDB 为什么要使用 B+ 树,而不是 B 树、Hash、红黑树或二叉树?
因为 B 树、Hash、红黑树或二叉树存在以下问题:
- Hash:虽然可以快速定位,但是没有顺序,IO 复杂度高;
-- 哈希索引适合等值查询,但是不无法进行范围查询;
-- 哈希索引没办法利用索引完成排序;
-- 哈希索引不支持多列联合索引的最左匹配规则 如果有大量重复键值得情况下,哈希索引的效率会很低,因为存在哈希碰撞问题。
【哈希索引:对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。 - B 树:不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少(有些资料也称为扇出),指针少的情况下要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低;
- 二叉树:树的高度不均匀,不能自平衡,查找效率跟数据有关(树的高度),并且 IO 代价高;
- 红黑树:树的高度随着数据量增加而增加,IO 代价高。
3. 相关总结
InnoDB存储引擎的最小存储单元为页, 1页存储数据大小为16K。数据库索引是存储在磁盘上的,当数据量比较大的时候,索引的大小可能有几G, 当我们查询的时候,不能把所有索引加载到内存中,能做的就是逐一加载每一个磁盘页(磁盘页对应索引树的节点),相对于磁盘IO的速度,在内存中对比的耗时几乎可以忽略,所以只要树的高度足够少,IO次数足够少,就可以提高查询性能。相比较于内部节点多一些也没有关系,仅仅多了几次内存交互,只要不超过磁盘页大小即可。【磁盘的IO次数是由索引树的高度决定的】
综合所述,InnDB 只有采取 B+ 树的数据结构存储索引,才能提供数据库整体的操作性能。B-树主要应用于文件系统以及部分数据库索引,非关系性数据库MongoDB