← 每日面试题 学习看板

什么是回表,怎么减少回表的次数?

面试题/03数据库中间件/01MySQL/03索引设计与优化(核心面试点)/什么是回表,怎么减少回表的次数?.md

面试记录 2026-09-17

题目:什么是回表,怎么减少回表的次数?

难度:low

标签:db/mysql/index, mysql/index, difficulty/low

评分:⭐⭐⭐☆(3/5)

我的回答

所谓回表,就是使用索引,非主键索引去查询数据。查询的数据到叶子层其实是没有主数据的,这时候它的数据需要从主数据去拿,这个拿的过程就是回表。回表就是通过子索引找到主键 ID,然后再通过主键 ID 去聚簇索引里边拿到主数据,然后展现出来。想要缩减回表的话,首先可以做覆盖索引,也就是说将要展示的数据统一加到索引里边来,在索引的底层直接可以拿到整体的数据,这样可以减少回表的次数。另外就是降低查询的数据,少量的数据获取也可以降低回表,因为回表是通过数据去查主表、主键索引的位置。数据量少了,对应的回表次数也就少了。

点评

优点:

不足:

补充:

完整讲解

第一部分:知识重点剖析

核心考点定位:理解 InnoDB 二级索引与聚簇索引的关系,掌握减少回表的工程手法。

知识点拆解:

  1. 什么是回表:InnoDB 采用聚簇索引,二级索引叶子节点只存「索引列 + 主键」。查询用二级索引时,先从二级索引找到主键 ID,再拿主键回聚簇索引 B+ 树查一次完整行,这个"回头找主表"的动作叫回表。
  2. 回表为什么慢:每次回表都是一次独立的 B+ 树查找,如果行数据不在 Buffer Pool 里就是随机磁盘 IO。100 万行匹配只 LIMIT 10,MySQL 仍可能回表 100 万次(在排序/过滤前)。
  3. 减少回表三板斧:
  1. 反模式:把大字段(TEXT/BLOB、长 VARCHAR)放进索引;SELECT * 让覆盖索引失效;给低基数字段单独建索引导致扫描后大量回表。

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. Extra 列里的 Using index 和 Using index condition 有什么区别?
  1. **一条 SELECT * FROM t WHERE a=? ORDER BY b LIMIT 10 有索引 (a,b),还会有回表吗?如何彻底消除?**
  1. 为什么 InnoDB 推荐用自增主键而不是 UUID 做聚簇索引?

第三部分:面试者参考回答(口语化)

面试官您好,回表是 InnoDB 的一个特有现象。InnoDB 把数据存在聚簇索引里,而二级索引的叶子节点只存"索引列 + 主键 ID",不存完整行。所以当我们用二级索引查数据时,先在二级索引的 B+ 树上定位到主键 ID,再拿这个 ID 回聚簇索引 B+ 树查一次完整行,这次回头查主表的过程就叫回表。回表贵,是因为每一次都是一次独立的 B+ 树查找,如果行数据不在 Buffer Pool 里,就是随机磁盘 IO;而且回表次数取决于索引扫描到的行数,不是最终 LIMIT 数量,一条 LIMIT 10 的查询可能回表几百万次。

减少回表主要有三个手段。第一是覆盖索引,把 SELECT 需要的列都放进一个索引里,这样在二级索引叶子节点就能拿到全部数据,EXPLAIN 里会显示 Using index,完全不需要回表。第二是延迟关联,写法是先在一个子查询里只查主键 ID,配合 WHERE 和 ORDER BY 和 LIMIT,然后再拿这批主键 JOIN 回主表拿完整行,这样回表次数就被压到 LIMIT 那个数。第三是索引下推 ICP,这是 MySQL 5.6 加的特性,对于范围查询,把非索引列的过滤条件推到索引扫描阶段做,减少需要回表的行数,EXPLAIN 里能看到 Using index condition。

工程上还要注意几个坑,一是不要在索引里放大字段和长字符串,会让索引膨胀;二是尽量避免 SELECT *,它会让覆盖索引失效;三是主键最好用自增整数,UUID 会让二级索引里存的主键无序,回表时随机 IO 更多。

https://chat.deepseek.com/share/5e7y27yvn1p1s5d5s1