1017 字
约 3 分钟
5
S11-B05 · 索引基础:类型、结构与最左前缀
适用读者:知道"加索引会快"但说不清"为什么"的人。
前置:S11-B02。
实测环境:MySQL 8.0.46 / InnoDB(s11lab,2026-11-05)。
覆盖旧文:1229(64) 1230(51) 1231(49) 845(133) 843(71) 838(105) 2401(668) 1827(156) = 1,297 点。
覆盖扩展:E-S11-005(B+ 树与聚簇索引)。
上一篇:S11-B04 · 增删改与表管理
下一篇:S11-B06 · 事务与隔离级别。
1. 一句话结论
InnoDB 的索引是 B+ 树:主键索引的叶子节点存整行(聚簇索引),二级索引的叶子节点存主键值(需回表)。所以"索引给的是定位能力,不是数据本身"。
聚簇索引(主键) 二级索引(idx_age)
[ 30 ] [ 30 ]
/ \ / \
[1..][..] [..] [id=5][id=9] ← 叶子存主键
↑ 叶子存整行 ↓ 需要回表
| 索引 | 叶子存什么 | 查询代价 |
|---|---|---|
| 聚簇(主键) | 整行数据 | 一次定位 |
| 二级索引 | 主键值 | 定位 + 回表 |
| 覆盖索引 | 查询所需列都在索引里 | 不用回表 |
2. 索引类型(A-845/A-1229)
| 类型 | 说明 |
|---|---|
| 聚簇索引 | 主键(没有主键则用唯一非空索引/隐藏 rowid) |
| 二级索引(辅助) | 普通/唯一/前缀 |
| 联合索引 | 多列组合,遵守最左前缀 |
| 全文索引 | FULLTEXT(中文需分词插件) |
| 哈希索引 | InnoDB 自适应哈希(内部,不可手动建) |
"唯一索引 vs 主键索引"(A-843):主键唯一且非空、一张表只有一个;唯一索引允许 NULL、可有多个。
3. 实测:索引到底省了什么
-- 有 idx_age
explain select id,name from t_user where age=30;
type: ref key: idx_age rows: 250 Extra: NULL
-- 函数包裹(失效)
explain select id,name from t_user where age+1=31;
type: ALL key: NULL rows: 20000 Extra: Using where
扫描行数 250 vs 20000 —— 这就是索引的价值,也是"写法决定性能"的直接证据。
4. 最左前缀(A-857)
联合索引 (a, b, c):
| 查询条件 | 能否用索引 |
|---|---|
a / a,b / a,b,c |
✅ |
b / c / b,c |
❌(跳过最左列) |
a, c |
✅ 只用 a 部分 |
a + b 范围 |
范围之后的列失效 |
判据:"联合索引的第一列,是最高频的过滤条件吗?" 不是 → 索引设计错了。
5. 索引不是越多越好
| 代价 | 说明 |
|---|---|
| 写入变慢 | 每次写都要维护所有索引 |
| 空间 | 索引也是数据 |
| 优化器选择变难 | 索引多可能导致选错 |
| DDL 变慢 | 加列/改表要重建索引 |
判据:"这个索引有对应的查询吗?" 没有 → 删掉(A-1232 的删除索引)。
6. 五个误区
| 误区 | 真相 |
|---|---|
| "索引越多查询越快" | 写变慢、优化器可能选错 |
| "二级索引直接存数据" | 存主键,需回表 |
| "没有主键就没索引" | InnoDB 会用隐藏 rowid 建聚簇索引 |
| "联合索引任意列都能单独用" | 必须遵守最左前缀 |
| "唯一索引就是主键索引" | 唯一索引可多个、允许 NULL |
7. 自检
- 聚簇索引与二级索引的叶子节点各存什么?
- 什么是回表?什么时候不需要回表?
- 联合索引
(a,b,c)哪些查询能用? - 索引过多的三个代价?
- 主键与唯一索引的差别?
8. 下一篇
S11-B06 · 事务与隔离级别
索引讲完,下一篇讲"并发下读到什么":四个隔离级别、MVCC,以及实测的可重复读。
本篇属于系列《S11 · 数据库与 SQL》。旧文来源:A-1229/1230/1231/845/843/838/2401/1827;扩展点 E-S11-005。EXPLAIN 为 MySQL 8.0.46 实测。
S11-B05 · 索引基础:类型、结构与最左前缀
https://www.clxhxhhr.top/posts/5329/ 评论
0 条
还没有评论,先写一条吧。