深入了解MySQL中的B+树索引

深入了解MySQL中的B+树索引

之前在数据结构中了解到了B+树,现在在学习MySQL的过程中优再次遇到了B+树,所以今天专门写一篇文章来阐述一下我所理解的B+树,希望能帮助到大家。

二叉排序树、平衡二叉树和B树

在了解B+树之前我们有必要了解一下一些较为基础的数据结构。

首先是二叉排序树。

假设,你现在维护着一个身份证信息和姓名的表,需要根据身份证号查找对应的名字,这时对应的二叉排序树的示意图如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n5CLV1kx-1598173378481)(C:\Users\jiangzhe\AppData\Roaming\Typora\typora-user-images\image-20200823140354000.png)]

二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。这样如果你要查ID_card_n2 的话,按照图中的搜索顺序就是按照 UserA -> UserC -> UserF -> User2 这个路径得到。

但是二叉搜索树有一个问题就是很容易受插入元素顺序的影响,导致树结构退化成为链表。试想一下如果我们依次插入100,200,300,400,500,此时建成的树节点全部都只有右孩子而没有左孩子,整体来看二叉树退化成为了链表,导致插入和查找的效率都退化成为线性O(N)。

因此接下类有了平衡二叉树。 平衡二叉树在符合二叉查找树的条件下,还满足任何节点的两个子树的高度最大差为1,因此能够保证查询和插入的时间复杂度均是 O(logN)。平衡二叉树主要有四种旋转的方式来维持整个树的平衡,具体可以参考这篇博客https://blog.csdn.net/u013235478/article/details/50625677

平衡二叉树已经保证插入和查找的时间复杂度均为O(logN),但是同时还存在可以改进的地方。第一,就是维持平衡的条件较为严格,在进行插入的过程中很容易使左右两个子树的高度插大于1,导致旋转发生的次数较为频繁,因此我们可以放松一下平衡的条件,这就是大名鼎鼎的红黑树。红黑树的应用非常广泛,例如hashmap底层就是利用了红黑树,有兴趣的可以搜索更多资料来进行学习。第二,就是在数据库的场景下,平衡二叉树显得过于“瘦长”,因为每个节点最多只有两个叉,我们可以想象成每次读取一次磁盘块只能读取一层的数据,因此查询和更新数据时需要IO操作次数较多。

为了让一个查询尽量少地读磁盘,就必须让查询过程访问尽量少的数据块。那么,我们就不应该使用二叉树,而是要使用“N 叉”树。这里,“N 叉”树中的“N”取决于数据块的大小。 接下来就出现了B树,B-Tree结构的数据可以让系统高效的找到数据所在的磁盘块。B-Tree中的每个节点根据实际情况可以包含大量的关键字信息和分支,如下图所示为一个3阶的B-Tree:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZLArMI0e-1598173378483)(C:\Users\jiangzhe\AppData\Roaming\Typora\typora-user-images\image-20200823143435943.png)]

每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

模拟查找关键字29的过程:

  1. 根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】
  2. 比较关键字29在区间(17,35),找到磁盘块1的指针P2。
  3. 根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】
  4. 比较关键字29在区间(26,30),找到磁盘块3的指针P2。
  5. 根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】
  6. 在磁盘块8中的关键字列表中找到关键字29。

分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于平衡二叉树缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。

InnoDB中的B+树

在 MySQL的索引引擎InnoDB 中使用了 B+ 树索引模型,所以数据都是存储在 B+ 树中的。既然B树的效率都已经足够好,为什么还要有B+树呢?我们首先来看一 下B+树的结构。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mPxn5322-1598173378485)(C:\Users\jiangzhe\AppData\Roaming\Typora\typora-user-images\image-20200823144103523.png)]

从之前B-Tree结构图中可以看到每个节点中不仅包含数据的key值,还有data值。而每一个页的存储空间是有限的,如果data数据较大时将会导致每个节点能存储的key的数量很小,当存储的数据量很大时同样会导致B-Tree的深度较大,增大查询时的磁盘I/O次数,进而影响查询效率。在B+Tree中,所有数据记录节点都是按照键值大小顺序存放在同一层的叶子节点上,而非叶子节点上只存储key值信息,这样可以大大加大每个节点存储的key值数量,降低B+Tree的高度。

B+Tree相对于B-Tree有几点不同:

  1. 非叶子节点只存储键值信息。
  2. 所有叶子节点之间都有一个链指针。
  3. 数据记录都存放在叶子节点中。

通常在B+Tree上有两个头指针,一个指向根节点,另一个指向关键字最小的叶子节点,而且所有叶子节点(即数据节点)之间是一种链式环结构。因此可以对B+Tree进行两种查找运算:一种是对于主键的范围查找和分页查找,另一种是从根节点开始,进行随机查找。

每一个索引在 InnoDB 里面对应一棵 B+ 树 。假设,我们有一个主键列为 ID 的表,表中有字段 k,并且在 k 上有索引。

这个表的建表语句是:

create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;

表中 R1~R5 的 (ID,k) 值分别为 (100,1)、(200,2)、(300,3)、(500,5) 和 (600,6),两棵树的示例示意图如下。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aAkwTvf5-1598173378493)(C:\Users\jiangzhe\AppData\Roaming\Typora\typora-user-images\image-20200823145425153.png)]

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。 主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。根据上面的索引结构说明,我们来讨论一个问题:基于主键索引和普通索引的查询有什么区别?

  • 如果语句是 select * from T where ID=500,即主键查询方式,则只需要搜索 ID 这棵 B+树;
  • 如果语句是 select * from T where k=5,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表。

也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询 。

B+ 树为了维护索引有序性,在插入新值的时候需要做必要的维护。以上面这个图为例,如果插入新的行 ID 值为 700,则只需要在 R5 的记录后面插入一个新记录。如果新插入的 ID 值为400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。而更糟的情况是,如果 R5 所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。

除了性能外,页分裂操作还影响数据页的利用率。原本放在一个页的数据,现在分到两个页中,整体空间利用率降低大约 50%。当然有分裂就有合并。当相邻两个页由于删除了数据,利用率很低之后,会将数据页做合并。合并的过程,可以认为是分裂过程的逆过程。

参考

1.MySQL索引原理https://blog.csdn.net/u013235478/article/details/50625677

2.丁奇,MySQL实战45讲

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值