P28 聚集索引和非聚集索引
面试题:什么是聚集索引(聚簇索引)和非聚集索引(二级索引)?有什么区别?
1. 核心定义
- 聚集索引(Clustered Index):数据行直接存储在索引的叶子节点上。InnoDB 中主键索引就是聚集索引,"索引即数据,数据即索引";
- 非聚集索引(二级索引/辅助索引):叶子节点存的是索引列的值 + 主键值,不直接存整行数据。
2. InnoDB 的两种索引
聚集索引(主键索引)
text
B+ 树叶子节点 = 完整数据行- 表必须有一个聚集索引:
- 有主键 → 主键就是聚集索引;
- 没主键 → 选第一个非空唯一索引;
- 都没有 → 隐藏生成 rowid 作为聚集索引;
- 数据行按主键顺序物理存储(逻辑上)。
二级索引(普通索引/联合索引)
text
B+ 树叶子节点 = (索引列的值, 主键值)通过二级索引查数据需要回表:先用二级索引找到主键,再到聚集索引里查整行。
3. 区别对比
| 对比项 | 聚集索引 | 非聚集索引 |
|---|---|---|
| 叶子节点 | 整行数据 | 索引列 + 主键 |
| 数量 | 每表最多一个 | 每表可以多个 |
| 查询数据 | 直接得到整行 | 一般需回表 |
| 插入性能 | 主键乱序插入会页分裂 | 相对独立 |
| 覆盖索引 | 本身就是覆盖 | 索引列覆盖查询时可免回表 |
4. 高频追问
① 什么是回表(回表查询)
text
SELECT * FROM t WHERE name = 'x'; -- name 是二级索引
二级索引查到主键 → 聚集索引再查一次 → 回表② 什么是覆盖索引
查询的列全部在二级索引里,就不用回表:
sql
SELECT id, name FROM t WHERE name = 'x';
-- name 索引 = (name, id),id/name 都在索引里 → Using index,免回表③ 为什么 InnoDB 二级索引叶子存主键而不是行指针
主键不变,数据页移动/分裂时二级索引无需更新;若存行指针,数据搬迁会导致大量索引失效。
④ 主键为什么要用自增/有序的
聚集索引按主键有序存储,乱序主键(UUID)插入会导致频繁页分裂、索引碎片、性能下降。
一句话总结
聚集索引叶子存整行(InnoDB 主键索引),非聚集索引叶子存"索引列+主键";二级索引查数据通常要回表,用覆盖索引可以免回表,主键设计要有序以保插入性能。