覆盖索引指索引包含查询所需全部字段(SELECT、WHERE、ORDER BY、GROUP BY列),使MySQL直接从B+树叶子节点获取数据而无需回表;主键索引天然覆盖,二级索引需显式包含所有相关字段。

覆盖索引能避免回表,核心是让查询所需的所有字段都包含在索引中,这样 MySQL 直接从索引 B+ 树叶子节点拿到全部数据,无需再回聚簇索引查找行记录。
什么是覆盖索引
当一个索引包含了查询中 SELECT 列 + WHERE/ORDER BY/GROUP BY 涉及的列 时,该索引就称为“覆盖索引”。MySQL 优化器会优先选择它,因为执行计划中 Extra 字段会显示 Using index,表示只用索引没回表。
注意:主键索引(聚簇索引)本身存储完整行数据,所以任何基于主键的单列查询天然就是覆盖的;但普通二级索引默认只存索引列 + 主键值,因此要覆盖,就得把查询用到的字段全加进索引里。
如何设计覆盖索引
关键原则是:把 高频查询中 SELECT 的字段 + 过滤/排序/分组字段 合理组合进一个联合索引,且遵循最左前缀原则。
- 先放 WHERE 条件中的等值列(顺序可调,但需连续)
- 再放范围查询列(如 >、BETWEEN,最多只能有一个)
- 最后放 SELECT 和 ORDER BY 中的非条件列(即“覆盖”部分)
例如:查询 SELECT name, email FROM user WHERE status = 1 AND create_time > '2024-01-01' ORDER BY id;
推荐索引:INDEX idx_cover (status, create_time, name, email, id)。
其中 status 等值匹配,create_time 范围过滤,name/email/id 覆盖输出和排序——这样整条语句不回表。
验证是否生效
用 EXPLAIN 查看执行计划,重点关注两处:
- key:显示实际使用的索引名
- Extra:出现 Using index 才是真正覆盖;若看到 Using where; Using index,说明索引覆盖了 WHERE 但可能部分字段仍需回表;若出现 Using filesort 或 Using temporary,说明排序/分组未被索引完全支持,可能破坏覆盖效果
小技巧:用 SELECT * 很难走覆盖索引,尽量明确列出需要的字段,并确保它们都在索引中。
注意事项与限制
覆盖索引不是万能的,要注意以下几点:
- 索引越宽,占用空间越大,写入性能越低——别把大字段(如 TEXT、JSON)加进索引
- 联合索引字段数建议不超过 5 个,否则维护成本高、命中率下降
- LIKE 前导通配(
LIKE '%abc')无法使用索引,自然也无法覆盖 - OR 条件可能导致索引失效,建议改用 UNION 或重写为 IN
- NULL 值在索引中单独处理,含 NULL 的字段参与覆盖时需确认业务是否允许忽略或补默认值
不复杂但容易忽略。










