MySQL的底层数据结构

1,649 阅读6分钟

前言

还是关于面试的时候会提到的问题吧:

  1. 为什么会存在B-树?
  2. MySQL的底层数据结构是什么?
  3. 为什么要用B+树不用B树?
  4. 为什么用B+树存储索引而不是Hash索引?Hash索引O(1)不是更快吗?

B-树

首先要了解 B+树 的话,我们先看看为什么会存在B-树?

为什么会存在B-树?

这个问题经常会有人一脸懵逼,为什么会存在B树?啊?为什么?我咋知道为什么?我只知道它是什么,它与别人的区别,我咋知道为什么会存在B-树啊?因为它存在所以它存在吗。。。

那么到底为什么会存在B-树呢?, 我们可以看看B-树叫什么先,它又叫 多路搜索树

为什么是多路?

如果你有看过 红黑树是什么? 的话,你就可以知道,红黑树虽然保持了平衡,但是它无法避免的高度还是会很高,所以B-树的多路,主要目的就是为了 降低树的高度 嘛。

这里的话又有人会问了,那多路,无限多路下去最后不就是一个数组吗?为什么不直接用数组呢?

确实,无限多路下去确实就是一个有序数组了,但是打住,我们可以看看B-树实际应用在什么地方, 这里的话主要用在文件系统的索引比较多

那为什么文件系统索引不用红黑树或者有序数组呢?

对于文件系统我们可以知道,树的高度代表了磁盘IO的次数,红黑树我们首先可以排除了,太高。那有序数组不是更好?一次IO就完事了呗,不是更有效率。

但是我们文件系统的文件小还好说,但是文件大了的话,你不一定能一次性把它全部加载到内存中的呀。

如果一次性无法全部加载入内存应该如何查询?

这立马就明白了吧!这就是B-树的厉害之处呀, 多路存储 ,每次只加载一个节点,一步一步往下查找。B-树就是为此而存在的,它既保证了 高度低 ,又保证了 数据多 ,也就是我们常说的“矮胖”。

总结

所以我们知道,如果在内存中,红黑树确实比B-树更加高效,但是涉及到磁盘操作的话,B-树就显得更优秀了。

B-树的性质

上面说到了为什么会存在B-树,那么我们来看看B-树有什么性质。

这个 B-树 就叫 B树 而不叫 B减树

B-树 它是一种多路搜索树,一般M阶的B树主要特点有:

  1. 根节点至少有两个子女。
  2. 每个非根节点所包含的关键字个数k满足: M/2-1 <= k <= M-1。
  3. 除根节点外的非叶子节点的儿子树的个数满足 M/2 <= k <= M。
  4. 所有的叶子节点都位于同一层。

看起来确实有点复杂,不过没关系,我们来看看B-树的具体结构先:

B-树

这颗B树中,我们重点来看看(54,73)节点, 该节点有两元素,54和73,又有三个孩子分别是48、60、(92,105),可以看到这三个孩子是按照它的父节点区分开的,正好符合我们上面提到的B-树的特征。

B-树的查找

我们上面看到了B-树的大致结构,那么为什么要叫 多路搜索树 呢?它是如何实现高效的查询的?

我们可以就上面的树来查查看,加入我们要查找数字92。

第一次磁盘IO:

查找92-1

与46比较后第二次磁盘IO:

查找92-2

与(45,73)比较后第三次磁盘IO:

查找92-3

与(92, 105比较)找到92:

查找92-4

通过整个流程我们也可以看出,B-树在查询中的比较次数没有比二叉搜索树少多少,但B-树本身优化的点就不在这里。

B-树它的优化的重点在于 「 减少磁盘的IO次数 」 ,我们知道磁盘不是内存,磁盘刷新页的效率没有内存那么高效,所以减少磁盘的IO次数可以大大的提升查询的效率。

关于插入和删除操作就先不说了。

B+树

B+树的性质

B+树是B树的一种变形形式,B+树上的 叶子结点存储关键字以及相应记录的地址叶子结点以上各层作为索引 使用。一棵m阶的B+树定义如下:

  1. 每个节点最多有m个子女;
  2. 除根节点外,每个节点至少有 m/2 个子女,根节点至少有两个子女;
  3. 有k个子女的节点必有k个关键字。

这里重点说一下B+树与B树的主要区别:

  1. 数据的查找方式不同 ,B+树查询必须查找到叶子节点,B树只要匹配到即可不用管元素位置,因此B+树查找更稳定(并不慢)。

  2. 数据存储的位置不同 ,B+树的非叶子节点只是用来索引用的,所有数据都是存在叶子节点上,所以B+树的磁盘也可以容纳更多数据。

  3. B+树叶子节点是个链表 , 我们知道B+树的数据都在叶子节点,那么对于范围查找的情况,B-树就需要重复的中序遍历,而B+树只需要遍历叶子节点链表即可。

为什么会存在B+树?

老问题了,首先我们还是先看看B+树的应用场景。我们知道MySQL底层的数据结构用的就是B+树。

为什么B+树的结构要这么设计?非叶子节点索引?底层数据链表?为什么用B+树而不用B-树?

ok,我们考虑一下MySQL常用的查询就好了。

假设我们现在有个孩子表child,我按照ID排序选10条。应该怎么查?

如果是B-树的话,我们需要 多次中序遍历

如果是B+树的话,由于有链表结构,所以只需要确认首尾,通过链表就可以把数据取出来了。

比如这个图里,我查询46-61的所有节点:

B+树-查询-46-61

为什么用B+树存储索引而不是Hash索引?Hash索引它O(1)不是更快吗?

查询单条数据确实Hash索引快,但同上,B+树支持 范围查询 ,而Hash索引做不到。

而且数据库索引一般存储在磁盘中,加载进内存中如果数据量大的话 无法一次装入内存 ,B+树的设计可以允许数据 分批加载 ,同时树的高度较低,提高查找效率。

都结合网上资料加上自己的一些理解,如果有影响到他人的地方,可以联系我:fzfz2007@163.com