吃透 MySQL 索引选型:为什么是 B + 树?从二叉树到 B + 树的全解析

4 阅读3分钟

吃透 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,能存大量索引。
  • 聚簇索引:叶子节点存完整用户记录,主键索引。
  • 二级索引:叶子节点存主键,回表查询。