外观
如果查询的时候出现了回表,这个回表是怎么发生的
⭐ 题目日期:
阿里 - 2025/8/19
📝 题解:
当查询发生回表时,主要涉及非聚簇索引(或称为辅助索引)。回表是查询优化的一种策略,它发生在无法通过单个索引完成全部查询时。
什么是回表?
简单来说,回表就是MySQL在非聚簇索引上找到对应的数据行后,需要再次通过主键索引到主键对应的聚簇索引上,从而获取整行数据。这个“再次查询”的过程,就叫做回表。
回表发生的具体过程
我们以一个具体的例子来解释。假设有一个users
表,包含id
(主键)、name
、age
和city
等字段,并且在name
字段上建立了一个非聚簇索引。现在执行一个查询:SELECT * FROM users WHERE name = '张三';
。
回表的过程如下:
- 索引查找:首先,MySQL会在
name
这个非聚簇索引上,根据name = '张三'
这个条件进行查找。 - 获取主键值:非聚簇索引的叶子节点存储的不是整行数据,而是索引列的值(在这里是
name
)和对应的主键值(在这里是id
)。所以,在name
索引上找到'张三'
后,会得到对应的主键id
,比如id = 10
。 - 发生回表:由于我们
SELECT *
需要查询所有列的数据,而name
索引上只有name
和id
,所以MySQL会拿着第2步获取到的主键id = 10
,再去主键索引(聚簇索引)上进行第二次查找。 - 获取整行数据:主键索引的叶子节点存储了整行数据。MySQL通过
id = 10
在主键索引上定位到对应的叶子节点,从而取出该行的所有数据,包括name
、age
、city
等字段。 - 返回结果:将查找到的完整数据返回给用户。
如何避免回表?
避免回表的关键在于利用索引覆盖查询。
如果一个查询的所有需要查询的字段,都可以直接从索引中获取,而不需要再次访问主键索引去查找整行数据,那么这个查询就实现了索引覆盖,也就不会发生回表。
继续上面的例子,如果执行的查询是SELECT id, name FROM users WHERE name = '张三';
:
- 查询的字段
id
和name
都存在于name
这个非聚簇索引的叶子节点中。 - MySQL在
name
索引上找到'张三'
后,可以直接获取到id
,不需要再访问主键索引。 - 这样就避免了回表,查询效率会更高。
总而言之,回表是MySQL为了获取完整数据而进行的额外一次查询,而索引覆盖是避免回表、提升查询效率的常用优化手段。