不知大家心里有没有点 B-树概念 O(∩_∩)O哈哈~
MySQL 数据库大家都用过吧?里面的索引是基于什么数据结构?
当然大家也都知道索引主要是基于 Hash 表或者 B+ 树。
知识点:对于InnoDB表,数据文件ibd本身就是按B+树组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。
那大家知道 B+ 树的实现细节是什么样?B-树和 B+ 树有什么区别?MySQL 里面的索引为什么主要基于 B+树?
B-树和 B+ 树都是很基础的概念,大家有必要掌握一下。
要弄明白 B+ 树,咋们先要了解 B-树。需要注意的是,B-树就是 B 树,中间的横线并不是减号。
谁要是把 B-树读成 B 减树,那可就丢人了。
那大家来说说,数据库索引为什么要使用树结构存储呢?
也许你会认为这还不简单,树的查询效率高,而且保持有序。
既然这样,为什么索引没有使用二叉树来实现呢?(二叉树查询的时间复杂度是 0(logN),性能已经足够高了啊,难道 B 树可以比它更快?)
其实从算法逻辑上来讲,二叉树的查找速度和比较次数都是最小的。但是我们不得不考虑一个现实问题:磁盘 IO。
数据库索引是存储在磁盘上的,当数据量比较大的时候,索引的大小可能有几个 G 甚至更多。
当我们利用索引查询的时候,能把整个索引全部加载到内存吗?显然不可能。能做的只有逐一加载每一个磁盘页,这里的磁盘页对应着索引树的节点。
如果我们利用二叉查找树作为索引结构,情形是什么样呢?假设树的高度是 4,查找的值是 10,那么流程如下:
第 1 次磁盘 IO:
第 2 次磁盘 IO:
第 3 次磁盘 IO:
第 4 次磁盘 IO:
大家有没有从中看出,磁盘 IO 的次数是由什么决定的?
磁盘 IO 的次数是 4 次,索引树的高度也是 4.索引最坏的情况下,磁盘 IO 次数等于索引树的高度。
既然如此,为了减少磁盘 IO 次数,我们就需要把原本“瘦高”的树结构变得“矮胖”。这就是 B-树的特征之一。
B 树是一种多路平衡查找树,它的每一个节点最多包含 k 个孩子,k 被称为 B- 树的阶。k 的大小取决于磁盘页的大小。
下面来具体介绍一下 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 个孩子包含的元素的值域分划。
是不是觉得这条条框框的,看着好复杂。
别急,我们以一个 3 阶 B-树为例,来看看 B-树的具体结构。树中的具体元素和刚才的二叉查找树是一样的。
这棵树中,咋们重点来看(2,6)节点。该节点有两个元素 2 和 6,又有三个孩子 1,(3,5),8.其中 1 小于元素 2,(3,5)在元素 2,6 之间,8 大于(2,6),正好符合刚才所列的几条特征。
也许你会觉得这棵树长得可真奇怪,它真的能实现高效的查询吗?
那就让我来演示一下 B- 树查询的过程吧。假设我们要查询的数值是 5。
第 1 次磁盘 IO:
在内存中定位(和 9 比较):
第 2 次磁盘 IO:
在内存中定位(和 2,6 比较):
第 3 次磁盘 IO:
在内存中定位(和 3,5 比较):
通过整个流程我们可以看出,B-树在查询中比较次数其实不比二叉查找树少,尤其当单一节点中元素数量很多时。
可是相比磁盘 IO 的速度,内存中的比较耗时几乎可以忽略。所以只要树的高度足够低,IO 次数足够少,就可以提升查找性能。
相比之下节点内部元素多一些也没有关系,仅仅多了几次内存交互,只要不超过磁盘页的大小即可。这就是 B-树的优势之一。
就是这样,查询的过程明白了吧,那么 B-树是如何插入和删除的呢?
B-树插入新节点的过程比较复杂,而且分成多种情况。由于时间的关系,我们只举一个最典型的例子,假如我们要插入的值是 4。
自顶向下查找 4 的节点位置,发现 4 应当插入到节点元素 3,5 之间。
节点 3,5 已经是两元素节点,无法再增加。父亲节点 2,6 也是两元素节点,也无法再增加。根节点 9 是单元素节点,可以升级为两元素节点。于是拆分节点 3,5 与节点 2,6,让根节点升级为两元素节点 4,9,节点 6 独立为根节点的第二个孩子。
是不是发现,就为了插入一个元素,让整个 B-树的那么多节点都发生了连锁反应。
确实有些麻烦,但也正因为如此,让 B- 树能够始终维持多路平衡。这也是 B- 树的一大优势:自平衡。
下面我们再来说一说 B-树删除的过程。同样只举一个典型例子,删除元素 11。
自顶向下查找元素 11 的节点位置:
删除 11 后,节点 12 只有一个孩子,不符合 B- 树规范。因此找出 12,13,15 三节点的中位数 13,取代节点 12,而节点 12 自身下移成为第一个孩子。(这个过程称为左旋)。
以上就是 B-树的插入和删除,也是学习 B-树最绕的部分。没太看明白的小伙伴也不必心急,最关键的还是理解 B-树的核心思想。
那么,B-树都有哪些实际应用呢?
B- 树主要应用于文件系统以及部分数据库索引,比如著名的非关系型数据库 MongoDB。
而大部分关系型数据库,比如 MySQL,则使用 B+ 树作为索引。有关 B+ 树的知识,我们在 什么是 B+ 树❓做具体介绍。