1017 字
约 3 分钟
5
S11-B05 · 索引基础:类型、结构与最左前缀
2024-12-31
2026-11-07

适用读者:知道"加索引会快"但说不清"为什么"的人。
前置: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. 自检

  1. 聚簇索引与二级索引的叶子节点各存什么?
  2. 什么是回表?什么时候不需要回表?
  3. 联合索引 (a,b,c) 哪些查询能用?
  4. 索引过多的三个代价?
  5. 主键与唯一索引的差别?

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/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。