面试官:什么是覆盖索引?

MySQL 索引里有一个经常被问到的问题:

明明已经走了索引,为什么还需要回表?

之前讲过,回表就是在二级索引查到主键之后,再拿主键去聚簇索引把整行数据捞回来的那一步。

它本质上是在二级索引中找到主键后,再根据主键到聚簇索引中查询完整记录,因此会增加额外的索引访问和数据页读取成本。

那问题来了------有没有可能走了索引,但不需要回表?

有,这就是覆盖索引。

覆盖索引是什么

覆盖索引,指的是:

查询语句需要的所有字段,都已经在某个索引里找到了,不需要再回聚簇索引拿数据。

一次索引查询就拿到了所有需要的数据,没有二次查找。

为什么能实现?

InnoDB 的二级索引叶子节点,存的不只是索引字段的值,还有对应的主键值。

所以当查询的字段都在这个索引里,这条路径就被"覆盖"了。

举个容易理解的例子。

二级索引像图书馆的目录卡,上面写着书名和对应的书架号(主键)。

聚簇索引像书架上摆好的整本书(整行数据)。

如果目录卡上已经印着作者、出版年份这些你需要的信息,你就不必跑回书架去翻书------目录卡自己就够了。

这就是覆盖索引。

一个实际场景

假设有一张订单表:

sql 复制代码
CREATE TABLE `order` (
  order_id INT PRIMARY KEY,
  user_id INT,
  create_time DATETIME,
  status INT,
  amount DECIMAL(10, 2),
  INDEX idx_user_id (user_id)
);

order_id 是主键,对应聚簇索引。

user_id 是普通索引,叶子节点存的是 (user_id, order_id)。

现在有这么一条查询:

sql 复制代码
SELECT order_id, create_time
FROM `order`
WHERE user_id = 12345;

这条 SQL 需要的是 order_id 和 create_time 两个字段。

如果走 idx_user_id 索引,二级索引叶子节点里虽然有 user_id 和 order_id,但 没有 create_time。

拿到 order_id 之后,还得拿着它去聚簇索引把 create_time 捞回来。

这中间,就多了一次回表。

怎么改成覆盖

思路很直接:

让索引自己把结果给全,不需要再去聚簇索引里捞。

怎么做到?

在 user_id 上加一个复合索引,把 create_time 也包含进去:

sql 复制代码
ALTER TABLE `order` ADD INDEX idx_user_time (user_id, create_time);

加了索引之后,查询走 idx_user_time 这棵 B+ 树,叶子节点保存了 user_id 和 create_time,同时 InnoDB 的二级索引叶子节点还会保存对应的主键值 order_id。

查到 user_id = 12345 时,直接返回 order_id 和 create_time,不需要再回聚簇索引。

这就是覆盖索引的优化效果:

查询所需的数据都能直接从二级索引中获取,不需要再回表。

覆盖索引的边界

不是所有查询都能被覆盖。

有几个判断标准,值得在心里过一遍。

查询的字段必须全在索引里。

如果 SQL 里还选了个 status 字段,而索引里没有 status,那还是得回表。

覆盖是有条件的,不能无限扩大。

索引要贴合查询需求。

在满足查询条件的基础上,如果查询结果、排序或过滤所需的字段能够合理地包含在索引中,就有机会减少回表、排序等额外操作。

多列索引会占用更多存储空间,写入时也要维护索引,成本会上升。

因此,要结合查询收益、写入压力和索引大小综合判断,别为了覆盖而乱加索引。

最后串一下

覆盖索引的核心,就是"索引自己能把结果给全,不用再去聚簇索引里捞数据"。

它的前提是:

查询所需的字段都能够从索引中获取。

对于 InnoDB 的二级索引来说,主键值本身也会存储在二级索引叶子节点中,因此查询主键通常也可以被覆盖。

覆盖索引减少了从二级索引回到聚簇索引的访问,因此通常可以减少额外的页访问和 CPU 开销。

建索引不是越多越好,覆盖索引只是优化手段之一。

相关推荐
学长毕设2 分钟前
基于SpringBoot的野生动物公益保护平台设计与实现-附源码
java·spring boot·后端
梦里寻码23 分钟前
我用 NestJS + Vue3 写了一套完整的研发管理系统(58 表 / 229 API / 130 项断言,全开源
前端·后端·算法
鶴哥只手遮天31 分钟前
《Redis 8.10.3 深度剖析》系列 ·第 10 章 Hash 一:`listpack`、`hashtable` 与 `LISTPACK_EX`
redis·后端·开源
johnjincaaaa35 分钟前
WebAssembly 逆向实战:从 0 搞懂猿人学第 15 题
后端
Gopher_HBo39 分钟前
Go CPU 剖析:四角色白话机制 + 实测实验
后端
猿人谷1 小时前
Surrogate Model:让进化算法学会“预测”,为什么它正在成为智能优化的重要技术?
后端·算法·架构
the局外人2 小时前
LangChain ToolRuntime 入门:context、state 与 store 的实际用法
后端·langchain·agent
回家路上绕了弯2 小时前
当 AI 越来越能干,我们如何理解自己的价值?
后端
陈随易2 小时前
Node.js 2026上半年都有哪些性能提升?
前端·后端·程序员
hhcgchpspk2 小时前
flask服务端页面预防被爬措施
后端·python·flask·网络爬虫·防爬