为什么MySQL选择B+ Tree当索引?

153 阅读5分钟

本文首发于公众号:托尼学长,立个写 1024 篇原创技术面试文章的flag,欢迎过来视察监督~

在最近的技术面试中,这个问题被问到很多,但同学们往往给出的答案不太准确。

回答好这个问题,我们需要具备一些逆向思维,用排除法来证明其他数据结构做索引的缺点,也就证明了B+ Tree是最适合当数据库索引的。

所以,我们就先来盘一盘,使用Hash、Binary Tree、Red Black Tree、B Tree或Skip List作为数据库索引,到底会有哪些问题。

Hash(哈希)

MySQL InnoDB是支持手动创建Hash索引的,也具备自适应Hash索引的特性,只不过还是以B+ Tree索引为主。

图片

自适应Hash索引,是MySQL InnoDB为一些热点查询自动创建并管理的,旨在以O(1) 的时间复杂度完成查询操作。
但Hash索引只擅长于等值查询的场景,对其他场景的支持并不好,且存在Hash冲突的风险,不如B+ Tree均衡全面。

特性‌ ‌Hash索引‌ ‌B+ Tree索引‌
等值查询‌O(1)O(log n)
范围查询‌不支持 高效支持
排序分组‌ 需额外排序 天然有序
组合索引‌ 不支持最左前缀 支持最左前缀
‌冲突风险‌ 严重时影响性能不存在

Binary Tree(二叉树)

Binary Tree并不适合做索引,原因在于每个节点至多拥有两个子节点,数据多的话会导致树高急剧增加,IO代价太大。

甚至在极端情况下,插入的数据是有序的(递增或递减),二叉树会退化为链表,导致查询性能从 O(logn) 退化为 O(n)。

图片

Red Black Tree(红黑树)

Red Black Tree是一种‌自平衡的二叉搜索树‌(Balanced Binary Search Tree),通过特定的规则和颜色标记(红/黑)来维护树的平衡性,确保在最坏情况下基本操作(插入、删除、查找)的时间复杂度为 ‌O(log n)‌。

因此,Red Black Tree所面临的问题和Binary Tree一样,在数据多的话会导致树高急剧增加,IO代价太大,并不适合做数据库索引。

图片

B Tree(B树)B+ Tree索引是B Tree索引的一种变体,两者存在如下两点主要区别:
(1)B Tree索引是“全数据节点”模式,在非叶子结点和叶子结点上都存储键值和数据,其中非叶子结点还会存储子节点的指针。

B+ Tree索引是“叶子结点数据”模式,只在叶子结点会存储键值和数据,非叶子结点只存储键值和子节点的指针。

(2)B+ Tree索引的叶子节点会通过指针连接形成链表。
两者直观比较如下图所示:

B Tree索引

图片

B+ Tree索引

图片

两者对比如下,从中我们可以看到,B+ Tree索引‌有一些B Tree索引所不具备的优势。

特性‌ ‌B Tree索引‌ ‌B+ Tree索引‌
查询效率树高可能略高,查询效率较低树高更低,查询效率更高
范围查询效率低,需遍历多个节点效率高,通过叶子节点的链表顺序访问
‌空间利用率较低,非叶子节点存储键值、数据、子节点指针较高,非叶子节点仅存储键值、子节点指针

Skip List(跳表)

Skip List一种可以进行二分查找的有序链表,在原有的有序链表上面增加了多级索引,通过索引来实现快速查找。

我们都知道,Redis ZSet的底层数据结构,就是通过Skip List来实现对于Score的范围查询。

图片

从上图中可以看到,B+ Tree和Skip List都是通过自上而下的查询方式提升性能的,且在最下面的一层包含了所有的数据,其有序性可更好地支持范围查询。

两者对比如下,从中我们可以看到,B+ Tree索引‌具备更多优势。

特性‌ ‌Skip List索引‌ ‌B+ Tree索引‌
查询效率树高很高,查询效率低树高更低,查询效率更高
新增操作根据随机函数确定层数,性能高有旋转和维持树平衡的开销,性能低
空间开销较高(多层指针冗余)较低
事务支持实现复杂,一致性难保证天然适配 MVCC 和 ACID

最后再解释一下两种数据结构的查询效率。
B+ Tree是扇出很高的多叉树结构,每个结点是一个16k的数据Page,按照每行数据1k大小进行计算,三层树高可存放2000万行数据,读一次数据只需要进行三次磁盘IO操作。

而Skip List则是一种链表结构,一个节点存储一行数据,若同样存储2000万数据的话,Skip List二分查找需要2的24次方,也就是读一次数据需要24次磁盘IO操作。

而一般情况下,我们的业务系统都属于读多写少型的,读写比例大概是9:1,很难接受Skip List这么多的IO次数。

结语

因此,从多种索引结构综合来看,B+ Tree虽然不是在各个方面最优秀的,却是各个方面没有短板的,所以主流数据库都选择它作为主要索引。