MySQL中InnoDB索引数据结构(B+树)详解

mysql的innodb的索引的B+树逐步讲解

  • B树
  • B+树
  • B树和B+树的不同点
  • 聚集索引 VS 非聚集索引
  • 总结(面试题)
    • 1.为什么不使用二叉查找树?
    • 2.为什么不使用平衡二叉树?
    • 3.为什么不使用B树?
    • 4.为什么MySQL选择B+树做索引

B+ 树: 是由二叉查找树,平衡二叉树和B树演化而来
二叉查找树: 任何节点的左节点的值都小于该节点,右节点都大于该节点。
为了避免二叉查找树的极端情况,即太高瘦,引入了平衡二叉树。
平衡二叉树: 又称 AVL 树,在满足二叉查找树特性的基础上,要求每个节点的左右子树的高度差不能超过 1。不平衡的时候会通过调整节点进行平衡,即要矮胖。

二叉查找树和平衡二叉树较为熟悉,不详细说,主要记录B树和B+树。

B树

因为数据存储在内存容易丢失,所以我们存储数据的话都是存在磁盘这种外围设备中。
但和内存相比,从磁盘中读取数据的速度会慢上百倍千倍甚至万倍,所以我们要想办法尽量减少读磁盘的次数。
另外,从磁盘中读取数据时,都是按照磁盘块来读取的,并不是一条一条的读。
那如果我们能尽量把更多的数据存放在一个磁盘块中,那么我们读取一次磁盘就可以读取更多的数据,从而减少读取磁盘的次数。
如果我们用树这种数据结构作为索引的数据结构,那我们每查找一次数据就需要从磁盘中读取一个节点,也就是我们说的一个磁盘块。
而平衡二叉树是每个节点只存储一个键值和数据的
那说明什么?
说明每个磁盘块仅仅存储一个键值和数据!那如果我们要存储海量的数据呢?
也就会导致二叉树的节点特别多,树的高度也特别高。
最终当我们需要查找数据的时候就要进行多次的磁盘IO查找,效率极低!

故 为了解决这种缺陷,我们就设计了一种每个节点可以存储多个键值和数据的平衡树,即B树。
MySQL中InnoDB索引数据结构(B+树)详解_第1张图片
图中的每个节点称为页
页就是我们上面说的磁盘块,在 MySQL 中数据读取的基本单位都是页,所以我们这里叫做页更符合 MySQL 中索引的底层数据结构。

跟平衡二叉树相比,B树的每个节点存储了更多的键值(key)和数据(data),每个节点可以拥有更多的子结点,子结点的个数通常称为 阶,上图的B树即为 3阶B树。
注意:B树的节点包含了键值和数据两部分,每个数据在树中只出现一次。

B+树

B+ 树是对 B 树的进一步优化。
MySQL中InnoDB索引数据结构(B+树)详解_第2张图片

B树和B+树的不同点

  1. B+ 树非叶子节点上是不存储数据的,仅存储键值,而 B 树节点中不仅存储键值,也会存储数据.
    这样的原因是在数据库中页的大小是固定的,即每个节点的大小是固定的,InnoDB 中页的默认大小是 16KB。如果不存储数据,就能在一个节点中存储更多的键值,即子节点更多(对应树的阶数也更大),树也会变得更矮更胖,我们查找数据的时候进行磁盘IO操作的次数就会更少,效率更快。
  2. B+ 树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的。
    这样的话,B+ 树使得范围查找,排序查找,分组查找以及去重查找变得异常简单。而 B 树因为数据分散在各个节点,要实现这一点是很不容易的。
    B+ 树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的
    上图中的 B+ 树索引就是 InnoDB 中 B+ 树索引真正的实现方式,准确的说应该是聚集索引。
    通过上图也可以看到,在 InnoDB 中,我们通过数据页之间通过双向链表连接以及叶子节点中数据之间通过单向链表连接的方式可以找到表中所有的数据。

聚集索引 VS 非聚集索引

什么是聚集索引呢?在 MySQL 中,B+ 树索引按照存储方式的不同分为聚集索引和非聚集索引

  1. 聚集索引(聚簇索引):以 InnoDB 作为存储引擎的表,表中的数据都会有一个主键,即使你不创建键,系统也会帮你创建一个隐式的主键。这是因为 InnoDB 是把数据存放在 B+ 树中的,而 B+ 树的键值就是主键,在 B+ 树的叶子节点中,存储了表中所有的数据
    这种以主键作为 B+ 树索引的键值而构建的 B+ 树索引,我们称之为聚集索引。
  2. 非聚集索引(非聚簇索引):以主键以外的列值作为键值构建的 B+ 树索引,我们称之为非聚集索引。

非聚集索引与聚集索引的区别
在于非聚集索引的叶子节点不存储表中的数据,而是存储该列对应的主键
想要查找数据我们还需要根据主键再去聚集索引中进行查找,这个再根据聚集索引查找数据的过程,我们称为回表。
即查找数据顺序是:先从非聚集索引找到主键->再根据主键到聚集索引找到对应的数据

总结(面试题)

MySQL的索引结构为什么是B+树?而不是其他

1.为什么不使用二叉查找树?

可能出现高高瘦瘦“一条龙”的景象,把二叉查找树退化为一个链表,相当于全表扫描,查找元素发挥不了二叉排序树的优势,只能按照链表的形式查找,高度太高了,查找效率不稳定。

2.为什么不使用平衡二叉树?

平衡二叉树解决了二叉树高度太高,查找效率不稳定的问题。但是,平衡二叉树的每个节点只存储一个键值和数据,如果数据非常的多(大多数情况下数据是海量的),二叉树的结点将会非常多,高度也会及其高,去磁盘取数据的次数就多,查找效率降低。

3.为什么不使用B树?

B树相对于平衡二叉树,优势在于每个节点存储了更多的键值(key)和数据(data),并且每个节点拥有更多的子结点,高度就会降低,B树在提高了IO性能的同时并没有解决元素遍历效率低下的问题,在找数据时需要遍历整个B树,为解决这个问题引出了B+树。
而且和B树相比,B+树的非叶子节点是值存储键值的,不存储数据,这样的话B+树的一个节点就可以存储更多的节点,使得树变得更加矮胖,从而查找效率更高。

4.为什么MySQL选择B+树做索引

  1. B+树的磁盘读写代价更低
    B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。
  2. B+树的查询效率更加稳定
    由于非叶子结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。
  3. B+树更便于遍历
    由于B+树的数据都存储在叶子结点中,非叶子结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。
  4. B+树更适合基于范围的查询
    B树在提高了IO性能的同时并没有解决元素遍历的我效率低下的问题,正是为了解决这个问题,B+树应用而生。B+树只需要去遍历叶子节点就可以实现整棵树的遍历。而且在数据库中基于范围的查询是非常频繁的,而B树不支持这样的操作或者说效率太低。

参考文章:
https://blog.csdn.net/qq_45814695/article/details/117171536
https://blog.csdn.net/qq_42410605/article/details/122517769

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