首页/数据/数据库速查/覆盖索引(Using index)
性能与调优57 条

覆盖索引(Using index)

查询列全部命中索引列时无需回表:Extra 显示 Using index;把高频查询的返回列并入联合索引是常见提速手段,注意索引体积膨胀。

数据库速查数据更新于 2026-10-13

覆盖索引是什么

覆盖索引指一个查询需要的所有列都能从索引里拿到,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、长文本)塞进覆盖索引,会让索引体积接近表本身,得不偿失。覆盖索引适合「列少、行多」的查询形态。
高频写入的表上加覆盖索引要评估写放大:每次写入都要维护更多索引页,读变快的同时写可能变慢,最终要靠真实压测数据来定。

易错点

  • 把大列塞进覆盖索引:索引膨胀到接近表的体积
  • 只看 EXPLAIN 变快不看写负载:写放大被忽略,高峰期写入能力下降
  • 用 SELECT 星号还期待覆盖索引生效:返回全部字段,天然无法覆盖
  • 联合索引列顺序随手写:前导列与查询条件不匹配,索引根本用不上

数据来源与参考

  • MySQL 8.0 Reference Manual: Covering Indexes

相关工具

​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌