数据库:B+ 树 / 数据库索引的底层支柱

B+ 树是 MySQL(InnoDB)以及绝大多数关系型数据库采用的索引数据结构。理解 B+ 树,就能理解数据库性能的底层逻辑。

我用表格 + 图示的方式,把 B+ 树的核心知识点系统梳理出来。

一、为什么数据库要用 B+ 树?

数据结构 查询复杂度 磁盘 I/O 次数 适用场景 数据库是否采用
有序数组 O(log n)(二分查找) 很少(内存友好) 静态数据 ❌ 数据插入成本太高
链表 O(n) 简单队列 ❌ 太慢
AVL/红黑树 O(log n) ~log n(可能有几十次) 内存数据结构 ❌ 树太高,磁盘 I/O 多
B 树 O(log n) 较少(节点大) 文件系统、部分数据库 ⚠️ 范围查询性能不如 B+ 树
B+ 树 O(log n) 最少(节点大且矮) 绝大多数关系型数据库 ✅ 最佳选择
哈希表 O(1)(等值查询) 1 次 等值查询场景 ✅ 用于 Memory 引擎或二级索引

核心结论

B+ 树的优势在于 矮(树层数少)+ 平(节点数据量大),磁盘 I/O 次数最少,最适合磁盘存储的数据库。

二、B+ 树的核心结构特征

特征 B 树(平衡多路搜索树) B+ 树(B-树的变体) 为什么 B+ 树更好
数据存储位置 所有节点(根、枝、叶)都存数据 只有叶子节点存数据 非叶子节点可以存放更多索引,降低树高
叶子节点关系 叶子节点独立 所有叶子节点通过双向链表相连 范围查询无需回溯父节点,效率极高
冗余存储 不会冗余存储 父节点冗余存储子节点最小键值 便于快速定位数据
叶子节点数据 存完整行数据 存主键 + 行指针 InnoDB 中二级索引存主键值

图示对比(简化)

B 树结构:

复制代码
        [20 | 数据]
       /     |     \
[10 | 数据] [30 | 数据] [40 | 数据]

B+ 树结构:

复制代码
        [20] [40]
       /   |     \
[10][20] [30][40] [40][50]
    ↓       ↓       ↓
  链表连接 →→→→→→→→→→

三、B+ 树的三个核心优势

优势 说明
磁盘 I/O 最少 B+ 树节点大(通常 16KB),一次 I/O 能加载大量索引;树层数低(通常 3-4 层),查询只需 3-4 次 I/O
范围查询极快 找到下限值后,沿叶子节点链表向前遍历即可,不需要回溯父节点
查询性能稳定 所有查询最终都会到达叶子节点,遍历路径长度总是固定的(从根到叶)

这意味着: 查询 1 行和查询 1000 行的路径长度相同,时间复杂度总是 O(log n)。

四、InnoDB 的 B+ 树与数据存储

InnoDB 中,B+ 树用于两种主要索引:

索引类型 B+ 树叶子节点存储内容 说明
聚簇索引(主键索引) 存储完整行数据 表数据本身就是一颗 B+ 树,以主键作为索引键
二级索引(非主键索引) 存储主键值 查询时先找到主键,再回表查询完整数据(称为"回表")

InnoDB B+ 树结构示意

复制代码
         聚簇索引 B+ 树
    [主键1] [主键2] [主键3]
       |       |       |
    叶子节点:存储完整行数据
       ↓       ↓       ↓
   (id=1, name=张三, age=25)
   (id=2, name=李四, age=30)
   (id=3, name=王五, age=28)

         二级索引 B+ 树
    [姓名] [姓名] [姓名]
       |      |      |
    叶子节点:存储对应主键值
       ↓      ↓      ↓
   (张三→id=1) (李四→id=2) (王五→id=3)

五、为什么 3 层 B+ 树能支撑 2000 万行数据

以 InnoDB 默认 page_size = 16KB 为例:

层级 作用 存储内容 数量
第 1 层(根节点) 指向子节点的指针 约 1200 个键值对 1 个节点
第 2 层(枝节点) 指向叶子节点的指针 约 1200 个键值对 1200 个节点
第 3 层(叶子节点) 存储数据行 约 16 行数据/页 1200 × 1200 = 1,440,000 个节点

关键推导

非叶子节点可存约 1200 个 索引键值(每行约 13 字节)

叶子节点可存约 16 条 完整行数据(假设每行约 1KB)

3 层 B+ 树最多可存储:

1200(第1层)× 1200(第2层)× 16(叶子节点数据行数)= 23,040,000 行

所以,3 层 B+ 树大约支撑 2000 万行数据 ,查询需要 3 次磁盘 I/O

六、B+ 树 vs B 树 vs LSM 树

对比维度 B+ 树 B 树 LSM 树
写性能 一般(需随机写入) 一般 高(顺序写入,先写内存)
读性能 高(稳定 O(log n)) 较高 一般(需合并多个 SSTable)
范围查询 极高(叶子节点链表) 中等(需回溯父节点) 一般(需扫描多个文件)
事务支持 ✅ 支持 ✅ 支持 ⚠️ 较弱
适用数据库 MySQL、PostgreSQL、Oracle 部分文件系统 Cassandra、HBase、LevelDB、RocksDB
适用场景 OLTP(在线交易系统) 文件系统索引 OLAP、日志存储、写入密集型

七、B+ 树知识速查表

问题 答案
B+ 树是什么? 一种平衡多路搜索树,数据库索引的标准结构
和 B 树的主要区别? B+ 树只在叶子节点存数据,B 树所有节点都存数据
为什么不用二叉树? 二叉树太高,磁盘 I/O 多,B+ 树矮而平
叶子节点的作用? 存储全部数据(聚簇索引)或主键值(二级索引),并通过链表连接
范围查询为什么快? 找到下限后,沿叶子节点链表遍历即可
一个节点通常多大? 16KB(MySQL InnoDB 默认页大小)
查询需要几次磁盘 I/O? 3-4 次(树高对应 I/O 次数)
什么时候用到 B+ 树? 执行 SELECT 语句时,数据库自动使用 B+ 树索引加速查询

八、B+ 树在数据库中的实际应用

场景 B+ 树的作用
主键等值查询 SELECT * FROM users WHERE id = 100 → 走聚簇索引,3 次 I/O
主键范围查询 SELECT * FROM users WHERE id BETWEEN 1 AND 100 → 定位起点后沿叶子链表遍历
二级索引查询 SELECT * FROM users WHERE name = '张三' → 先走二级索引找到主键,再回表
ORDER BY SELECT * FROM users ORDER BY id → 直接遍历叶子节点链表,无需额外排序
COUNT(*) 叶子节点链表快速统计行数(非精确)

九、一句话总结

B+ 树是数据库索引的灵魂。它通过矮平的树形结构 + 叶子节点链表,用最少的磁盘 I/O 实现了最稳定的查询性能。

如果理解了 B+ 树,你对数据库索引设计、查询优化、分库分表等高级话题的理解都会更加透彻。

相关推荐
梦想的旅途21 小时前
企业微信二次开发实战:基于RPA接口的私域中台架构设计与选型指南
数据库·企业微信·rpa
许彰午1 小时前
87_Python Django模型与数据库
数据库·python·django
—Miss. Z—2 小时前
计算机二级MySQL选择题考点Ⅱ
数据库·mysql·oracle
敖行客 Allthinker2 小时前
IM 融合专题:后端架构师的核心修炼
java·开发语言·数据库
翔云1234562 小时前
MySQL 中 CURRENT_TIMESTAMP 到底取的是 INSERT 时间,还是 COMMIT 时间?
数据库·mysql
矜持的左手2 小时前
硬件故障后数据文件大小不对故障处理—Oracle碎片扫描恢复
数据库·oracle
欢呼的太阳10 小时前
数据库设计Step by Step (10)——范式化
服务器·数据库·oracle
喜欢的名字被抢了11 小时前
MySQL基础入门:从零理解数据库与SQL
数据库·mysql·教程
Elastic 中国社区官方博客12 小时前
如何比较两个 Elasticsearch 索引并找出缺失的文档
大数据·运维·数据库·elasticsearch·搜索引擎