索引原理
hardMySQL索引B+树哈希索引
索引是什么
索引是帮助 MySQL 高效查找数据的数据结构。没有索引时,查询需要全表扫描(逐行检查),有索引时可以快速定位到目标行。
比喻:索引就像书的目录,通过目录可以快速翻到第 358 页,而不用从第 1 页逐页翻找。
为什么使用 B+ 树
MySQL InnoDB 索引使用 B+ 树,而不是二叉树、红黑树或哈希表。
为什么不用二叉搜索树 / 红黑树?
二叉树的高度太高。100 万条数据,红黑树高度约 20 层,每层一次磁盘 I/O → 20 次 I/O。B+ 树是多叉树(通常每个节点上千个子节点),3~4 层就能存储上亿数据。
为什么不用 Hash?
Hash 索引只支持等值查询(= / IN),不支持范围查询(<、>、BETWEEN)、排序、模糊匹配。而 B+ 树天然支持范围查询。
为什么不用 B 树而用 B+ 树?
| 特性 | B 树 | B+ 树 |
|---|---|---|
| 数据存储 | 所有节点都存数据 | 只有叶子节点存数据 |
| 叶子节点链表 | 无 | 叶子节点用双向链表连接 |
| 非叶子节点 | 存数据+指针 | 只存索引键+指针 |
| 范围查询 | 需要中序遍历整棵树 | 沿叶子链表顺序扫描 |
| 磁盘 I/O | 较多(节点大、扇出小) | 较少(扇出大、树矮) |
B+ 树结构:
[10 | 20 | 30] ← 非叶子节点(只存键)
╱ │ ╲
[3|5|8] [12|15|18] [22|25|28] ← 非叶子节点
╱ │ ╲ ╱ │ ╲ ╱ │ ╲
叶 叶 叶 叶 叶 叶 叶 叶 叶 ← 叶子节点(存数据)
◀═══════════════════════════════════▶ 双向链表连接
B+ 树非叶子节点不存数据 → 能放更多键 → 扇出更大 → 树更矮 → 更少的磁盘 I/O。
InnoDB 索引类型
聚簇索引(主键索引)
InnoDB 的表数据按照主键顺序存储,主键索引的叶子节点就是完整的数据行:
主键索引(聚簇索引):
[5 | 10]
╱ │ ╲
[1|3] [6|8] [11|15]
╱ ╲ ╱ ╲ ╱ ╲
[id=1 ] [id=3 ] [id=6 ] [id=8 ] [id=11 ] [id=15 ]
[完整行 ] [完整行 ] [完整行 ] [完整行 ] [完整行 ] [完整行 ]
◀════════════════════════════════════════════════════▶
二级索引(非聚簇索引)
二级索引的叶子节点存储的不是完整数据行,而是主键值:
二级索引(如 name 索引):
[李 | 王]
╱ │ ╲
[陈|李] [刘|王] [赵|周]
╱ ╲ ╱ ╲ ╱ ╲
[陈,id=3] [李,id=1] [刘,id=8] [王,id=6] ...
◀════════════════════════════════════════▶
通过二级索引查询时,先查到主键值,再通过回表到聚簇索引查完整数据行。
生产高频题
为什么 MySQL 用 B+ 树做索引?
(1) B+ 树非叶子节点不存数据,扇出大,2~4 层可存上亿数据,磁盘 I/O 少;(2) 叶子节点通过双向链表连接,范围查询高效;(3) 所有查询都走到叶子节点,性能稳定。
聚簇索引和非聚簇索引的区别?
聚簇索引的叶子节点存储完整的数据行(数据和索引在一起),一个表只有一个聚簇索引(通常是主键)。非聚簇索引叶子节点存储主键值,查完整数据需要回表。