你以为面试官只是想考你索引知识?不,其实他想看看你能不能把底层原理讲清楚。今天小米我就来聊聊,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:
这时候:
- 这个SQL命中了 idx_name_age 索引。
- WHERE 和 SELECT 用到的字段(name和age)都在这个索引里。
- 所以不需要去主键索引那里回表,直接从二级索引就能拿到数据。
这就是经典的覆盖索引命中。
但是如果你执行的是:
抱歉,虽然WHERE条件命中了idx_name_age,但你要拿email,它不在这个索引的叶子节点中,只好通过name索引查到主键,然后回主键索引的B+树去拿整行数据。
所以结论就是:
覆盖索引不需要回表,非覆盖的二级索引——需要!
回到那个问题:聚簇索引和覆盖索引到底回不回表?
我们再复读一下题干:
B+树在满足聚簇索引和覆盖索引的时候是否需要回表查询数据?
答案来了:
聚簇索引:不需要回表
- 因为数据就在叶子节点上,查到的就是你想要的完整数据。
- 它就是数据本体。
覆盖索引:也不需要回表
- 因为你用到的字段都能在某个辅助索引中找到,无需回到主键索引去拿整行数据。
那什么时候才会回表?
主要就三种场景:
1、命中的是普通二级索引,但返回字段不在索引里
→ 需要拿主键去主键索引回表。
2、联合索引命中不全
比如:索引是 (name, age),你查的是WHERE age=18,没命中最左前缀,就不走索引。
3、查询结果多字段返回,不全在索引中
即使命中索引,如果字段缺失,也要回表。
彩蛋:执行计划怎么看有没有回表?
运行 SQL 时,加一句:
看结果里的 Extra 字段:
- 如果写着 Using index:说明是覆盖索引,不回表。
- 如果写着 Using where; Using index:还是不回表。
- 如果写着 Using where 或 Using index condition:可能回表,要看返回的字段在不在索引中。
为什么这个问题常出现在面试中?
其实面试官问这个问题,不是为了考你死记硬背,而是想看看你:
- 真的理解什么是B+树吗?
- 知道聚簇和非聚簇的区别吗?
- 能不能根据SQL写法判断是否回表?
- 明白如何写出更高效的SQL吗?
这些,都是高级MySQL工程师的基本素养。
总结:一张表说清回不回表
建议
别小看这种小题目,理解得越深,你写的SQL就越高效,对数据库调优也越有信心。
下次你再碰到“需不需要回表”这种问题,别慌,问自己三件事:
- 用的是不是主键?
- 查的字段都在索引里吗?
- 执行计划是怎么说的?
就能做出判断了!
END
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!
我们下次见!