B 树 vs B+ 树:为什么 MySQL 用 B+ 树,而不是 B 树?

🌳 B 树 vs B+ 树:为什么 MySQL 用 B+ 树,而不是 B 树?

B+ 树不是 B 树的"升级版",而是为"范围查询"而生的专用结构。

如果你学过数据结构,一定听说过 B 树(B-Tree)

如果你用过数据库,一定接触过 B+ 树(B+ Tree)

但你是否真正理解:

  • 它们到底有什么区别?

  • 为什么 MySQL、PostgreSQL、Oracle 等主流数据库都选择 B+ 树做索引

  • 文件系统(如 NTFS、ReiserFS)又为何偏爱 B 树?

今天,我们就从结构、查询、插入、删除、I/O 效率、适用场景六大维度,彻底讲透 B 树与 B+ 树的区别!


🔹 一、先看结构:根本差异在哪?

✅ B 树:所有结点都存数据

复制代码
        [50]
       /    \
[30,40]    [60,70]
 /  |  \     /  |  \
10  35 45   55 65 75
  • 每个内部结点既存索引,也存真实数据

  • 叶子结点和其他结点没有本质区别

  • 查找任意关键字,可能在任意层命中


✅ B+ 树:只有叶子存数据,内部只存索引

复制代码
        [50]
       /    \
    [30]    [60]
   /   \    /   \
[10,30] [40,50] [60,70] ← 所有数据都在这里!
  ↑     ↑     ↑
  └─── 叶子结点通过指针连成链表 ───┘
  • 内部结点仅作导航(索引),不存真实数据

  • 所有数据(记录或指针)只存在于叶子结点

  • 叶子结点之间用双向链表连接

💡 这个设计,是 B+ 树一切优势的起点!


🔹 二、六大核心区别详解

维度 B 树 B+ 树
1. 数据存储位置 所有结点都可存数据 仅叶子结点存数据
2. 叶子结点结构 普通结点,无特殊连接 通过指针连成有序链表
3. 查询效率 单点查询快(可能早停) 单点查询略慢(必须到叶子)
4. 范围查询 需中序遍历,效率低 链表顺序扫描,极高效
5. 磁盘 I/O 效率 内部结点混存数据,扇出小 内部结点纯索引,扇出更大 → 树更矮
6. 插入/删除稳定性 结构变化复杂 更稳定,分裂/合并仅影响局部

下面逐条展开!


✅ 区别 1:数据存储位置 → 决定一切

  • B 树 :每个结点包含 (key, data)

    → 插入一条记录,可能放在根、中间或叶子

  • B+ 校 :内部结点只存 key(用于导航),叶子存 (key, data)(key, pointer)

🌟 优势 :B+ 树的内部结点更"轻",同样磁盘块能存更多关键字 → 分支因子更大 → 树高更低

举例

假设一个磁盘页 4KB,每条记录 1KB,指针 8 字节。

  • B 树结点:最多存约 3 个 (key + data)

  • B+ 树内部结点:可存约 500 个 key + 指针(因无 data)

→ B+ 树高度可能只有 2~3 层,而 B 树需要 4~5 层 → I/O 次数更少


✅ 区别 2:叶子链表 → 范围查询的"核武器"

这是 B+ 树最被低估的设计!

复制代码
[10] → [20] → [30] → [40] → ...
 ↑_________________________↓
(双向链表)

当你执行:

复制代码
SELECT * FROM users WHERE id BETWEEN 100 AND 200;
  • B+ 树

    1. 一次查找定位到 100 的叶子

    2. 沿链表顺序读取,直到 200

      几乎 100% 顺序 I/O,缓存友好

  • B 树

    需要多次树遍历,关键字分散在不同结点

    大量随机 I/O,性能差

📊 实测:范围查询下,B+ 树比 B 树快 5~10 倍


✅ 区别 3:单点查询:B 树真的更快吗?

理论上,B 树可能在非叶子结点就命中数据,少走一层。

但现实中:

  • 数据库通常将 B+ 树的叶子存完整记录 (聚簇索引)或 存主键指针(二级索引)

  • 即使多走一层,树高本身很低(2~3 层),差异可忽略

  • 而 B+ 树更大的扇出反而可能让总层数更少

结论:单点查询性能基本持平,B+ 树不输!


✅ 区别 4:插入与删除的稳定性

  • B 树:插入可能导致任意层结点分裂,数据可能从叶子"上浮"到高层

  • B+ 树 :所有数据固定在叶子,分裂只发生在叶子或内部索引层,数据位置稳定

🛠️ 对数据库而言,"数据位置稳定"意味着:

  • 缓存命中率更高

  • 更新操作更可预测

  • 并发控制更简单


🔹 三、真实世界中的选择

系统 使用结构 原因
MySQL (InnoDB) B+ 树 高频范围查询(如分页、时间范围)
MongoDB B 树(早期),现用 WiredTiger(B+ 树变种) 早期支持嵌套文档,需灵活存储
PostgreSQL B+ 树(默认索引) 兼顾点查与范围查
Linux ext4 / XFS B 树或其变种(如 extent tree) 文件元数据大小固定,点查为主
Windows NTFS B+ 树 支持大目录快速遍历

💡 规律

  • 数据库 → 偏好 B+ 树(范围查询刚需)

  • 文件系统 → 多用 B 树或变种(元数据小,点查为主)


🔹 四、一张图总结核心差异

复制代码
                B 树                          B+ 树
          ┌─────────────┐              ┌─────────────┐
          │  K1, D1     │              │     K2      │ ← 内部结点:仅索引
          │  K2, D2     │              ├─────────────┤
          └──────┬──────┘              │ K1  │  K3   │
        ┌────────┴────────┐           ┌─┴─┐ ┌─┴─┐
   ┌────▼────┐      ┌────▼────┐    ┌──▼──▼─┐ ┌▼──▼──┐
   │K3,D3│K4,D4│    │K5,D5│K6,D6│    │K1,K2│ │K3,K4│ ← 叶子:存数据 + 链表
   └─────────┘      └─────────┘    └─────┬─┘ └─┬─────┘
                                          └─────→

🔚 结语:没有最好,只有最合适

  • B 树 :通用平衡树,适合点查询为主、数据均匀分布的场景(如内存索引、文件系统元数据)

  • B+ 树 :为磁盘 I/O 和范围查询优化 ,是现代数据库的标配

正如《数据库系统概念》所说:
"B+ 树是为磁盘存储时代量身定制的数据结构。"

下次当你写 WHERE id > 1000 LIMIT 100 时,记得感谢 B+ 树背后的那条叶子链表,它正默默为你省下数百次磁盘寻道!


📚 延伸阅读

  • 《Database Internals》第 3 章:B+ 树实现细节

  • MySQL InnoDB 聚簇索引 vs 二级索引

  • LSM-Tree:B+ 树的"竞争对手"(用于写密集场景)


❤️ 如果你觉得这篇推文帮你理清了 B 树与 B+ 树的迷思,欢迎 点赞、在看、转发

💬 评论区聊聊:你们公司用的数据库,底层索引是哪种结构?

相关推荐
杨间2 小时前
《排序算法全解析:从基础到优化,一文吃透八大排序!》
c语言·数据结构·排序算法
Remember_9932 小时前
【LeetCode精选算法】滑动窗口专题二
java·开发语言·数据结构·算法·leetcode
Gorgous—l3 小时前
数据结构算法学习:LeetCode热题100-动态规划篇(下)(单词拆分、最长递增子序列、乘积最大子数组、分割等和子集、最长有效括号)
数据结构·学习·算法
Remember_9933 小时前
【LeetCode精选算法】滑动窗口专题一
java·数据结构·算法·leetcode·哈希算法
Lueeee.4 小时前
v4l2驱动开发
数据结构·驱动开发·b树
漫随流水4 小时前
leetcode回溯算法(77.组合)
数据结构·算法·leetcode·回溯算法
超级大福宝5 小时前
【力扣200. 岛屿数量】的一种错误解法(BFS)
数据结构·c++·算法·leetcode·广度优先
一分之二~9 小时前
回溯算法--解数独
开发语言·数据结构·c++·算法·leetcode
不如语冰9 小时前
AI大模型入门1.1-python基础-数据结构
数据结构·人工智能·pytorch·python·cnn