跳转至

索引原理与 B+ 树

核心问题:为什么 MySQL 选择 B+ 树作为索引结构?它解决了什么问题?


它解决了什么问题?

没有索引时,查询一条数据需要全表扫描,时间复杂度 O(n)。数据量越大越慢,百万级数据查询可能需要数秒。索引通过预先排好序的数据结构,将查询复杂度降到 O(log n)。


为什么选 B+ 树?

对比项 B+ 树 哈希表 普通 B 树
范围查询 ✅ 叶子节点链表,高效 ❌ 不支持 ⚠️ 需要回溯
等值查询 ✅ O(log n) ✅ O(1) ✅ O(log n)
排序 ✅ 叶子节点有序 ❌ 不支持 ❌ 需要额外排序
磁盘 IO ✅ 非叶子节点不存数据,层数少 - ⚠️ 层数更多

B+ 树 vs B 树的关键差异:B+ 树非叶子节点只存键值不存数据,同样大小的磁盘页能存更多键值,树的层数更少,磁盘 IO 次数更少。一棵高度为 3 的 B+ 树,可以存储约 2000 万条数据,只需 3 次磁盘 IO。


B+ 树结构图

flowchart TD
    subgraph B+树索引结构
        Root["根节点 [30 | 60]"]
        N1["内部节点 [10 | 20]"]
        N2["内部节点 [40 | 50]"]
        N3["内部节点 [70 | 80]"]
        L1["叶子节点\n10→row_data\n20→row_data"]
        L2["叶子节点\n30→row_data\n40→row_data"]
        L3["叶子节点\n50→row_data\n60→row_data"]
        L4["叶子节点\n70→row_data\n80→row_data"]
    end

    Root --> N1
    Root --> N2
    Root --> N3
    N1 --> L1
    N1 --> L2
    N2 --> L3
    N3 --> L4
    L1 -.->|双向链表| L2
    L2 -.->|双向链表| L3
    L3 -.->|双向链表| L4

关键特点:叶子节点通过双向链表连接,范围查询(如 WHERE id BETWEEN 10 AND 50)只需找到起点,然后顺序遍历链表,无需多次回溯树根。


生活类比

MySQL 概念 生活类比
全表扫描 在图书馆逐本翻书找内容
B+ 树索引 图书馆的分类目录(先找大类,再找小类)
叶子节点链表 目录页之间有"下一页"指针,翻页很快

面试高频问题

Q:B+ 树相比 B 树有什么优势?为什么 MySQL 选择 B+ 树?

B+ 树非叶子节点不存数据,同样大小的磁盘页能存更多键值,树的层数更少,磁盘 IO 次数更少;叶子节点通过链表连接,范围查询只需顺序遍历,无需回溯。一棵高度为 3 的 B+ 树可存约 2000 万条数据,只需 3 次 IO。

Q:为什么不用哈希表做索引?

哈希表只支持等值查询,不支持范围查询和排序,而数据库中 BETWEENORDER BYLIKE 'xxx%' 等操作非常常见,B+ 树能全部支持。