吃透 MySQL 索引选型:为什么是 B + 树?从二叉树到 B + 树的全解析
目录
- 一、为什么索引要选对数据结构?
- 二、从线性到二叉:为什么不行?
- 1、有序数组 + 二分查找
- 2、二叉查找树(BST)
- 3、自平衡二叉树(AVL / 红黑树)
- 三、从二叉到多叉:B 树的出现
- 四、最终答案:B+ 树为什么是 MySQL 的选择?
- 1、结构优化
- 2、性能优势
- 3、InnoDB 中的 B+ 树
一、为什么索引要选对数据结构?
首先MySQL 的数据是持久化的,意味着数据(索引+记录)是保存到磁盘上,但是磁盘是毫秒级,内存访问是纳秒级,磁盘差了几十万倍。-- 磁盘 I/O 是性能瓶颈,所以索引的目标就是:尽量少的磁盘 I/O 次数。
磁盘读写的最小单位是扇区:512B,操作系统块:Linux 下默认 4KB(一次 I/O 读 8 个扇区)。
通过索引查找某行数据,就需要先从磁盘读取索引到内存,再通过索引从磁盘中找到某行数据,然后读入到内存,所以磁盘 I/O 次数越多,所消耗的时间也就越大。
索引的核心要求:
- 少磁盘 I/O:树的高度越低越好;
- 支持高效单值查询和范围查询。
二、从线性到二叉:为什么不行?
1、有序数组 + 二分查找
- 优点:查找快,O (log n)。
- 致命缺点:插入 / 删除要移动大量元素,在磁盘上性能灾难。
2、二叉查找树(BST)
左子树所有节点 < 节点<右子树所有节点
- 解决了插入问题,不用移动元素。
- 致命缺点:极端情况下会退化成链表,时间复杂度变回 O (n),树高失控,磁盘 I/O 次数暴增。
3、自平衡二叉树(AVL / 红黑树)
在二叉查找树基础上,每个节点只能有2个节点。
- 解决了退化问题,查询稳定在 O (log n)。
- 致命缺点:每个节点只有 2 个子节点,数据量大时树依然很高,磁盘 I/O 次数还是太多。
三、从二叉到多叉:B 树的出现
在自平衡二叉树,解决树高问题,不再限制一个节点就只能有 2 个子节点,而允许 M 个子节点 (M>2),从而降低树的高度。
B 树的每一个节点最多可以包括 M 个子节点,M 称为 B 树的阶,所以 B 树就是一个多叉树。比如 3 阶 B 树,每个节点最多 2 个数据、3 个子节点。
查询过程
- 在节点内的有序数据中二分查找,决定去哪个子节点。
- 树高降低,磁盘 I/O 次数显著减少。
B 树的缺点
- 每个节点都存了完整的记录数据,导致单次 I/O 读到的 “有效索引” 变少。
- 范围查询需要回溯访问多个节点的 I/O,产生更多I/O,效率不高。
四、最终答案:B+ 树为什么是 MySQL 的选择?
1、结构优化
- 非叶子节点只存索引:不存完整记录,这样一个磁盘块(页)能存更多索引,树高更低。
- 叶子节点存数据:并且用双向链表串联起来。
2、性能优势
- 单值查询:从根节点开始查询,直到找到对应的叶子节点再找其非叶子的数据,路径更短,I/O 更少。
- 范围查询:直接找到初始值对应叶子节点,遍历链表,无需再从根节点重新查找,效率极高。
- 插入 / 删除:有冗余节点,操作更简单,树结构变化小,自动平衡。
3、InnoDB 中的 B+ 树
- 数据页默认 16KB,能存大量索引。
- 聚簇索引:叶子节点存完整用户记录,主键索引。
- 二级索引:叶子节点存主键,回表查询。