Mysql 索引模型 B+ 树详解

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
RDS MySQL DuckDB 分析主实例,集群系列 8核16GB
简介: 首先,在了解 mysql 中的 B+ 树之前,我们需要搞懂什么是二叉树。二叉树是一种常见的非线形数据结构,数据是以一对多的形态组织起来的

一、认识二叉树


首先,在了解 mysql 中的 B+ 树之前,我们需要搞懂什么是二叉树。二叉树是一种常见的非线形数据结构,数据是以一对多的形态组织起来的,我画了一张图来帮助你理解:

~%YJS@2YSYB{][H9XPOCS{6.png

在二叉树中,有一种比较特殊的,也是最常用的二叉树,那就是二叉搜索树,也叫做二叉查找树。它最大的特点是:对于树中的任意一个节点,假如节点值为 x,其左子树节点的值必须小于 x,其右子树节点的值必须大于 x,就像下图的这几种数据排列结构:

Y%APWM9`1Z~B2O7I@M{7S@U.png

那为什么需要使用二叉搜索树这种结构呢,它有什么好处吗?我们知道,常见的线性表结构,例如链表,要查找一个数据,必须从头开始遍历链表,在最坏的情况下,需要遍历整个链表才能够找到需要的数据。

而使用二叉搜索树这种结构,在树结构趋于平衡的情况下,借助二分的思想,每次查找数据的时候,都会舍弃掉另一个子树,所以在平均情况下,我们只需要在 O(logn)(也就是树的高度)的时间复杂度内就可以查找到数据。


二、为什么会选择 B+ 树


在了解了二叉搜索树之后,我们就为学习 B+ 树打下了坚实的基础。只不过先别着急,我们再来明确一个问题,为什么 mysql 会选择 B+ 树做为其索引模型呢?其他的数据结构不行吗?

要搞懂这个问题,我们先想想,mysql 中最常见的操作是什么?既然是数据库,最常见的操作当然是数据查询了,好的,我以最常见的两条 sql 查询语句为例:

  • select * from T where id = 1;
  • select * from T where id > 10 and id < 20;

一个是等值查询,一个是范围查询。

支持快速查询的常见数据结构有哈希表、平衡二叉查找树、跳表,我们依次来看看这几种结构能否做为 B+ 树的索引模型。

如果使用哈希表,虽然等值查询非常高效,但是数据的排列是无序的,所以并不支持范围查询。

VH27S[VDB@XJM$X}R8[DQ7Y.png

如果使用平衡二叉查找树,例如红黑树、AVL 树等,可以在接近 O(logn) 的时间内找到数据,但是对于树结构来说,范围查询仍然是很低效的,因为只能中序遍历一棵树得到一个有序的数据集,然后再依次查找。

ER_JUA$VP7X2HCU2YTVAP3B.png

如果使用跳表,等值查询的效率和平衡二叉查找树差不多,并且也支持范围查询,例如下图中,我们查找节点 7(红色粗线为查找路径),如果需要范围查询的话,可以顺着原始链表依次遍历下去,因为链表节点之间是有序的。

IC8ZT[2V8$)0_0B4U({{F82.png

这样来说的话,跳表也是可以做为索引模型的,但 mysql 还是选择了 B+ 树,实际上 B+ 树和跳表的设计思想有一些类似的地方,我们现在来看看 B+ 树是什么样子的。


三、B+ 树模型



1. B+ 树的优点

对数据构建索引,我们可以使用平衡二叉查找树,并且稍微做一下改造,把树的叶子节点使用链表串联,并且是从小到达顺序排列的,那么这种结构就能够支持等值查询和范围查询了,如下图:

DRE%O6IN0FMHVCXNRTJX[HX.png

当查找到一个节点之后,我们继续向后遍历,就能够实现高效的范围查询了。值得一提的是,这里串联叶子节点的链表,应该使用双向链表,方便在数据查询后进行升序或者降序操作。

这种结构虽然高效,但存在一个致命的问题,那就是太消耗内存空间了。

假如我们给 1000 万条数据建立索引,每个节点假设大约占用 16 字节的空间,那么构建一个索引大概就需要 150MB 内存,实际上我们还会给很多张表的很多字段建立索引,这样的话内存空间消耗还是太大了。

所以我们可以根据空间换时间的思想,使用磁盘来代替内存,磁盘是一种慢速的存储设备,造价也比内存低廉很多,因此我们可以将数据存储到磁盘上,只不过这样数据查询的速度就会慢一些了。

针对这种数据存储的方式,如果我们还是用上述的那种二叉树结构的话,每访问一层节点就对应着一次磁盘 IO,那这样的查询速度还是太慢了。因此我们可以改造一下上图中的这个结构,将二叉变成 n 叉,这样每一层节点存储的数据变多了,树的高度也降低了,访问磁盘的次数变少了,相应的查询性能就能够得到提升。

比如存储 30 个数据,构建二叉树的高度是 5,而 5 叉树的高度仅为 3:

H0X}F5SFL[)P~O9)]Z88U64.png

如果数据量再大一点,就更能看出差别了,比如我们构建的是 100 叉树,那么存储 1 亿个数据,树的高度也只是 5 ,这样的话磁盘 IO 的操作次数就被大大的降低了。

那么在实际的应用中,到底应该构建多少叉树呢?是不是树的节点越多,即 n 越大越好?我们知道,操作系统对磁盘的访问是以页为单位读取的,每页的大小通常是 4KB,也就是说我们只需要将 n 叉树的每个节点存储为一页大小左右,这样每次访问都能够整页读取,不会进行多余的磁盘 IO 操作。

假如每页的大小可以存储 3 个数据,那么最终的 B+ 树结构就是这个样子:

SIFI(Z7JRTX}FZCN1LLL8RB.png


2. B+ 树的缺点

这样来看的话,似乎 B+ 树已经比较完美的解决了数据索引的问题,但是,天下没有免费的午餐,B+ 树对查询操作有了很大的提升,但同时也降低了数据插入和删除的效率。

这个问题似乎不难理解,当我们不断插入数据的时候,B+ 树中的节点肯定会越来越多,直到大于了页大小,这时,为了维护查询的效率,不产生多余的 IO 操作,我们不得不进行节点的重构。

假如叶子节点的数量是 m,当节点数量大于 m 的时候,该节点就会分裂,从叶子节点的最中间的那个节点,让其成为父节点,节点左右的值,分别成为新的左右子节点;如果上一层又超过了限制,则继续向上进行分裂,直到影响到根节点,参照下面的图就很容易理解了:

[7D2N)WSFGOGNY{]@LH{93C.png

删除也是类似的道理,当叶子节点过少,例如少于 m / 2 的时候,就可以将节点合并至旁边的兄弟节点。你可以自己参照插入的思路,想想删除是怎么进行节点重构的。

好了,这篇文章讲述了 mysql 的索引模型 B+ 树,首先需要了解一下二叉树,这是学习 B+ 树的前提,然后我以两个最常见的查询 sql,向你描述了为什么其他的常见数据结构不适合用来做索引,然后由此引出了 B+ 树。

根据数据查询和存储的特点,对平衡二叉树逐步改造成了 B+ 树,B+ 树对数据查询起到了很好的作用,但是它也带有副作用,那就是对插入删除操作有影响,于是需要进行节点的重构。

为了帮助你更深刻的理解并学习 B+ 树,这里贴一下其他关于 B+ 树的优秀文章:

https://zh.wikipedia.org/wiki/B%2B%E6%A0%91

https://zhuanlan.zhihu.com/p/27700617

https://www.cnblogs.com/nullzx/p/8729425.html

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
5月前
|
存储 SQL 关系型数据库
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
mysql底层原理:索引、慢查询、 sql优化、事务、隔离级别、MVCC、redolog、undolog(图解+秒懂+史上最全)
|
5月前
|
存储 关系型数据库 MySQL
MySQL数据库索引的数据结构?
MySQL中默认使用B+tree索引,它是一种多路平衡搜索树,具有树高较低、检索速度快的特点。所有数据存储在叶子节点,非叶子节点仅作索引,且叶子节点形成双向链表,便于区间查询。
191 4
|
7月前
|
存储 关系型数据库 MySQL
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
|
9月前
|
关系型数据库 MySQL 数据库
Mysql的索引
MYSQL索引主要有 : 单列索引 , 组合索引和空间索引 , 用的比较多的就是单列索引和组合索引 , 空间索引我这边没有用到过 单列索引 : 在MYSQL数据库表的某一列上面创建的索引叫单列索引 , 单列索引又分为 ● 普通索引:MySQL中基本索引类型,没有什么限制,允许在定义索引的列中插入重复值和空值,纯粹为了查询数据更快一点。 ● 唯一索引:索引列中的值必须是唯一的,但是允许为空值 ● 主键索引:是一种特殊的唯一索引,不允许有空值 ● 全文索引: 只有在MyISAM引擎、InnoDB(5.6以后)上才能使⽤用,而且只能在CHAR,VARCHAR,TEXT类型字段上使⽤用全⽂文索引。
|
5月前
|
存储 SQL 关系型数据库
MySQL 核心知识与索引优化全解析
本文系统梳理了 MySQL 的核心知识与索引优化策略。在基础概念部分,阐述了 char 与 varchar 在存储方式和性能上的差异,以及事务的 ACID 特性、并发事务问题及对应的隔离级别(MySQL 默认 REPEATABLE READ)。 索引基础部分,详解了 InnoDB 默认的 B+tree 索引结构(多路平衡树、叶子节点存数据、双向链表支持区间查询),区分了聚簇索引(数据与索引共存,唯一)和二级索引(数据与索引分离,多个),解释了回表查询的概念及优化方法,并分析了 B+tree 作为索引结构的优势(树高低、效率稳、支持区间查询)。 索引优化部分,列出了索引创建的六大原则
140 2
|
6月前
|
存储 关系型数据库 MySQL
MySQL覆盖索引解释
总之,覆盖索引就像是图书馆中那些使得搜索变得极为迅速和简单的工具,一旦正确使用,就会让你的数据库查询飞快而轻便。让数据检索就像是读者在图书目录中以最快速度找到所需信息一样简便。这样的效率和速度,让覆盖索引成为数据库优化师傅们手中的尚方宝剑,既能够提升性能,又能够保持系统的整洁高效。
170 9
|
7月前
|
机器学习/深度学习 关系型数据库 MySQL
对比MySQL全文索引与常规索引的互异性
现在,你或许明白了这两种索引的差异,但任何技术决策都不应仅仅基于理论之上。你可以创建你的数据库实验环境,尝试不同类型的索引,看看它们如何影响性能,感受它们真实的力量。只有这样,你才能熟悉它们,掌握什么时候使用全文索引,什么时候使用常规索引,以适应复杂多变的业务需求。
192 12
|
11月前
|
存储 关系型数据库 MySQL
MySQL索引学习笔记
本文深入探讨了MySQL数据库中慢查询分析的关键概念和技术手段。
717 81
|
8月前
|
SQL 存储 关系型数据库
MySQL选错索引了怎么办?
本文探讨了MySQL中因索引选择不当导致查询性能下降的问题。通过创建包含10万行数据的表并插入数据,分析了一条简单SQL语句在不同场景下的执行情况。实验表明,当数据频繁更新时,MySQL可能因统计信息不准确而选错索引,导致全表扫描。文章深入解析了优化器判断扫描行数的机制,指出基数统计误差是主要原因,并提供了通过`analyze table`重新统计索引信息的解决方法。
223 3
|
9月前
|
自然语言处理 关系型数据库 MySQL
MySQL索引有哪些类型?
● 普通索引:最基本的索引,没有任何限制。 ● 唯一索引:索引列的值必须唯一,但可以有空值。可以创建组合索引,则列值的组合必须唯一。 ● 主键索引:是特殊的唯一索引,不可以有空值,且表中只存在一个该值。 ● 组合索引:多列值组成一个索引,用于组合搜索,效率高于索引合并。 ● 全文索引:对文本的内容进行分词,进行搜索。

推荐镜像

更多