覆盖索引是什么
覆盖索引指一个查询需要的所有列都能从索引里拿到,InnoDB 不必再回到主键索引取整行数据,执行计划里 Extra 会显示 Using index。它省掉的正是最贵的环节——回表带来的一次随机读。把高频查询用到的返回列并入一个联合索引,通常能带来明显的提速,代价是索引体积变大、写入时需要维护更多索引页。
基本信息
| 判断依据 | EXPLAIN 的 Extra 中出现 Using index |
|---|---|
| 原理 | 索引中已包含查询所需全部列,免去回表 |
| 常用手段 | 把高频查询的返回列并入联合索引 |
| 代价 | 索引体积变大,写入维护成本上升 |
| 边界 | SELECT 星号天然破坏覆盖,大字段不适合并入 |
典型使用场景
- 列表页只取少量字段的高频查询
- 分页查询里避免每行都回表读取
- 统计类查询只读取索引列即可完成
- 把返回列很少但扫描量很大的查询改造成覆盖索引
- 评估新增索引的读收益与写放大之间的取舍
改造示例
改造示例
-- 原查询需要回表读取 status 与 amount
SELECT user_id, status, amount FROM appdb.orders WHERE user_id = 1;
-- 建立覆盖索引
ALTER TABLE appdb.orders ADD INDEX idx_cover (user_id, status, amount);
-- 再看执行计划:Extra 应出现 Using index
EXPLAIN SELECT user_id, status, amount FROM appdb.orders WHERE user_id = 1;
-- 对照组:查询全部列无法被覆盖,仍会回表
EXPLAIN SELECT * FROM appdb.orders WHERE user_id = 1;执行计划读法
| 现象 | 含义 | 处理方向 |
|---|---|---|
| Extra 为 Using index | 完全覆盖,无需回表 | 这就是目标状态 |
| Extra 为 Using index condition | 使用索引下推,但仍需回表 | 评估把返回列并入索引 |
| Extra 没有 Using index | 存在回表读取 | 按查询清单评估覆盖索引 |
| key 为 NULL | 没有使用索引 | 先解决条件与索引匹配的问题 |
| rows 偏大 | 扫描行数过多 | 调整联合索引的列顺序 |
回表次数是容易被忽略的成本:一个范围扫描命中十万行,最坏情况就是十万次随机读。覆盖索引直接把这笔开销消掉,收益随命中行数同步放大。
把大字段(备注、JSON、长文本)塞进覆盖索引,会让索引体积接近表本身,得不偿失。覆盖索引适合「列少、行多」的查询形态。
高频写入的表上加覆盖索引要评估写放大:每次写入都要维护更多索引页,读变快的同时写可能变慢,最终要靠真实压测数据来定。