你以为面试官只是想考你索引知识?不,其实他想看看你能不能把底层原理讲清楚。今天小米我就来聊聊,B+树、聚簇索引、覆盖索引和“回表查询”之间到底是啥关系!

面试突袭:一颗简单的面试题,竟然藏着一整棵B+树?

“你了解MySQL的B+树吗?”

“当然,主键索引和辅助索引都是用B+树结构实现的,对吧?”

“那如果一个查询条件命中的是聚簇索引,或者命中的是覆盖索引,还要回表查询数据吗?”

……

我顿了一下,这题看起来简单,但细想下来,居然有点杀伤力。作为一个已经面了十几轮的社招老兵,我突然想起了两年前的一个故事。

故事回放:那个B+树惹的祸

那是我第一次面阿里社招岗,当时我信心满满,自我介绍都还没说完,面试官直接来了一句:

“说说看,B+树满足聚簇索引和覆盖索引的时候是否需要回表?”

我脑袋一懵,只记得自己支支吾吾地说:“这个……要看是不是联合索引吧……”

面试官看了我一眼,温和地笑了笑说:

“没关系,等你理解了什么是聚簇索引、什么是覆盖索引,再来答这个问题,你就明白了。”

那天我没过,但从此对“回表”两个字,记忆深刻。

场景再现:B+树是怎么工作的?

首先我们得知道:MySQL用的B+树到底是啥?

MySQL中InnoDB存储引擎使用的是B+树索引结构

  • 所有的数据都保存在叶子节点
  • 所有的索引搜索路径都必须走到叶子节点才能找到目标。
  • 内部节点只负责存储键值和指向下一层的指针。

B+树的结构非常适合磁盘读取,因为它IO少、查找快、范围查询效率高

聚簇索引:数据和主键绑定在一起

InnoDB的主键索引其实就是一个聚簇索引

  • 它的叶子节点保存的是整行数据
  • 所以通过主键查找某一行,不需要回表,因为整行数据就在叶子节点上。

这就是聚簇索引的核心特点:数据和主键在一棵树里,物理上在一起。

二级索引:又称为非聚簇索引

  • 二级索引(比如对name字段建立的索引)B+树的叶子节点,保存的是索引列+主键值
  • 你如果只靠name来查,但又需要返回除name之外的字段,那就必须通过主键值再去主键B+树上回表查询整行数据

这种回到主键B+树去取整行数据的过程,我们就叫——回表

再说回“覆盖索引”:回表到底需不需要?

我们接着聊另一个主角:覆盖索引(Covering Index)

简单说就是:

如果你查的所有字段都能在某个辅助索引的叶子节点中被包含,那么就不需要回表。

举个栗子:

表 user(id, name, age, email)

我们建立了一个索引:KEY idx_name_age(name, age)

然后执行 SQL:

MySQL社招面试题:B+树满足聚簇索引和覆盖索引时,还要回表查询吗?_数据

这时候:

  • 这个SQL命中了 idx_name_age 索引。
  • WHERE 和 SELECT 用到的字段(name和age)都在这个索引里。
  • 所以不需要去主键索引那里回表,直接从二级索引就能拿到数据。

这就是经典的覆盖索引命中

但是如果你执行的是:

MySQL社招面试题:B+树满足聚簇索引和覆盖索引时,还要回表查询吗?_数据_02

抱歉,虽然WHERE条件命中了idx_name_age,但你要拿email,它不在这个索引的叶子节点中,只好通过name索引查到主键,然后回主键索引的B+树去拿整行数据

所以结论就是:

覆盖索引不需要回表,非覆盖的二级索引——需要!

回到那个问题:聚簇索引和覆盖索引到底回不回表?

我们再复读一下题干:

B+树在满足聚簇索引和覆盖索引的时候是否需要回表查询数据?

答案来了:

聚簇索引:不需要回表

  • 因为数据就在叶子节点上,查到的就是你想要的完整数据。
  • 它就是数据本体。

覆盖索引:也不需要回表

  • 因为你用到的字段都能在某个辅助索引中找到,无需回到主键索引去拿整行数据。

那什么时候才会回表?

主要就三种场景:

1、命中的是普通二级索引,但返回字段不在索引里

→ 需要拿主键去主键索引回表。

2、联合索引命中不全

比如:索引是 (name, age),你查的是WHERE age=18,没命中最左前缀,就不走索引。

3、查询结果多字段返回,不全在索引中

即使命中索引,如果字段缺失,也要回表。

彩蛋:执行计划怎么看有没有回表?

运行 SQL 时,加一句:

MySQL社招面试题:B+树满足聚簇索引和覆盖索引时,还要回表查询吗?_主键_03

看结果里的 Extra 字段:

  • 如果写着 Using index:说明是覆盖索引,不回表
  • 如果写着 Using where; Using index:还是不回表。
  • 如果写着 Using where 或 Using index condition:可能回表,要看返回的字段在不在索引中。

为什么这个问题常出现在面试中?

其实面试官问这个问题,不是为了考你死记硬背,而是想看看你:

  • 真的理解什么是B+树吗?
  • 知道聚簇和非聚簇的区别吗?
  • 能不能根据SQL写法判断是否回表?
  • 明白如何写出更高效的SQL吗?

这些,都是高级MySQL工程师的基本素养。

总结:一张表说清回不回表

MySQL社招面试题:B+树满足聚簇索引和覆盖索引时,还要回表查询吗?_字段_04

建议

别小看这种小题目,理解得越深,你写的SQL就越高效,对数据库调优也越有信心。

下次你再碰到“需不需要回表”这种问题,别慌,问自己三件事:

  • 用的是不是主键?
  • 查的字段都在索引里吗?
  • 执行计划是怎么说的?

就能做出判断了!

END

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!

我们下次见!