极高 进阶
覆盖索引与回表#
一句话答案#
覆盖索引指查询字段全在索引中无需回表,explain 中 Extra 显示 Using index,是 SQL 优化的重要手段。
核心要点
回表过程: 二级索引查到主键值 → 主键索引查完整行数据
优化: 建联合索引覆盖 SELECT 的字段 → 避免回表 → 性能大幅提升
面试回答(2分钟版)
先说回表:InnoDB 二级索引叶子节点只存索引列值和主键值,查询需要的字段不全在索引中时,就要拿主键值再去聚簇索引查完整行数据,这个二次查询过程就是回表。回表代价在于每次都是随机 IO,结果集大时大量回表严重影响性能。覆盖索引是避免回表的关键优化手段:查询所有字段都包含在索引中时,直接从索引获取数据不需回表。判断方法是看 EXPLAIN 的 Extra 列,出现 Using index 就是覆盖索引。实际优化中根据高频查询建联合索引实现覆盖,比如 SELECT name, age FROM user WHERE city=‘北京’,建 (city, name, age) 联合索引即可覆盖。所以要避免 SELECT *,按需查字段才能利用覆盖索引。但也不要为了覆盖建特别宽的索引,索引越宽写入维护成本越高,要在读写性能间做权衡。
追问与易错
追问方向:
- “怎么判断用了覆盖索引?”→ EXPLAIN 的 Extra 列显示 Using index 表示使用了覆盖索引,数据直接从索引获取无需回表
- “覆盖索引为什么提升性能?”→ 避免了二级索引到聚簇索引的回表操作,减少随机 IO 次数;索引通常比数据行小得多,相同页能缓存更多记录,Buffer Pool 命中率更高
- “联合索引顺序对覆盖索引有影响吗?”→ 覆盖索引只要求查询字段都包含在索引中,与列顺序无关;但列顺序影响最左前缀是否满足,设计时需同时兼顾 WHERE 过滤和字段覆盖
易错点:
- ❌ SELECT * 也能走覆盖索引——不行
- ❌ 为了覆盖建很宽的联合索引——影响写入