哈喽,大家好,我是小米,一个31岁的大哥哥,坐标南京,喜欢研究数据库,也喜欢在技术中讲故事。今天要跟大家分享一个真实故事——关于“B树索引的数据结构”这个看似常见却足以让人掉坑里的社招面试题!
故事的主角就是我自己,一个被B树“支配”过的男人。
那个秋天,我差点在B树上翻车
事情发生在上一次跳槽的时候。那是一家大厂的社招面试,岗位是“数据库方向的后端开发”,招聘信息上写得明明白白:“熟悉MySQL索引原理者优先”。
我心想,“这我不就刚刚看完一堆InnoDB索引的视频嘛,安排!”
面试官笑着说:
“你可以简单说说MySQL中的B树索引是个什么结构吗?它为啥用B+树而不是红黑树或哈希表?”
听上去是不是很基础?当时我也是这么觉得的。
但你知道吗,当你需要用通俗的语言,把背后的数据结构讲清楚,还要回答‘为什么不是别的’,那可不是简单事。
那一刻我突然卡壳了。B树和B+树的概念在我脑子里搅成一团,满脑子只有“平衡树”“多路搜索”“磁盘I/O”,但就是没法条理清晰地表达出来……
于是,面完回家的我,下定决心,一定要把这个问题彻底搞懂,然后写成一篇文章,帮自己也帮大家。
现在,这篇文章来了!
B树和B+树,它们不是一回事!
很多人(包括曾经的我)都误以为 MySQL 的索引结构就是 B 树。其实不然,MySQL 中 InnoDB 的索引使用的是 B+ 树。
那我们先从“B树”和“B+树”的区别说起。
1、B树(Balanced Tree)
B树是多路搜索树(Multi-way Search Tree),跟我们熟悉的二叉树不一样,它的每个节点可以有多个孩子。这有啥用?
它可以减少树的高度!
在数据库这种“磁盘访问很慢”的场景中,我们希望树的层数越少越好,毕竟每下探一层就可能要一次磁盘I/O。
B树的特点:
- 每个节点最多有m个子节点(m阶B树)
- 每个节点存储 k 个关键字(key),其中 ceil(m/2)-1 <= k <= m-1
- 所有叶子节点不一定在同一层
- 每个节点的关键字按顺序排列,便于搜索
- 插入、删除会保持树的平衡性
2、B+树(B Plus Tree)
B+树是 B 树的一个变种,也是数据库中真正用到的索引结构。它有哪些改变呢?
B+树的特点:
- 所有 数据都存储在叶子节点,内部节点只存储索引(也就是key)
- 所有叶子节点在同一层,并且用链表串起来
- 内部节点可以看作是“路标”,不存数据
- 查找范围、区间非常高效
举个不那么严谨的例子:
如果说 B 树是一本每页都能看到内容的书,B+树就是封面目录页 + 全部内容集中在一起的“正文页”,中间用目录来导航。
为什么MySQL不用哈希索引、红黑树?
我们常听人说:“数据库为什么不直接用哈希表?查找更快啊!”
我也曾这么天真地想过。
来,我们一起从面试官的角度看:
1、哈希表不支持范围查询!
数据库可不光是查一个ID呀,我们经常查的是:
SELECT * FROM user WHERE age BETWEEN 20 AND 30;
哈希表压根就没顺序,想查个范围就得“扫表”了,效率直线拉跨。
2、红黑树太“矮小”,每个节点只放一个key
红黑树是“平衡二叉搜索树”的一种,每个节点只存一个 key。而磁盘访问代价很大,如果树层数多,IO频繁,性能就会受到影响。
而 B+树每个节点能存好多个 key,大大降低了树的高度,这就是数据库“亲儿子”。
MySQL中B+树到底长啥样?
想象你现在在写一张“用户表”,给 id 字段建了主键索引。InnoDB 会把这张索引组织成一棵B+树:
这个例子只是示意图,实际中每个页(节点)大小是16KB,能放成百上千个key。树的高度往往只有3~4层。
那MySQL如何用这棵树来查数据呢?
查找过程:
- 从根节点开始,读取关键字范围(比如找21)
- 找到20~30这条路径
- 跳到相应子节点页,继续查
- 到达叶子节点,获取完整数据(主键索引)或主键地址(辅助索引)
是不是有点“二分查找 + 跳转页 + 顺序访问”的味道?
这正是B+树的厉害之处:查找效率高、范围查询顺畅、磁盘I/O少!
B+树的优点,用人话讲就是这三点!
为了让大家记住,我总结成一个口诀:
多关键、少跳层,一链到底查区间!
- 多关键(多分支):每个节点能存大量key,降低了树的高度
- 少跳层(磁盘友好):树高低就意味着磁盘IO少,数据块读得快
- 一链到底(叶子有序):叶子节点排好序,还用链表连起来,做范围查时效率高得离谱
这几个特点,完美契合数据库高并发、高读写、高范围查询的特点。
一个简单的问题:聚簇索引和非聚簇索引,也跟B+树有关!
这个是很多人忽略的点,其实InnoDB的B+树索引还分两种:
1、聚簇索引(clustered index)
- 主键索引就是聚簇索引
- 数据行真实存在于B+树的叶子节点
- 查主键时,不需要二次跳转,速度最快
2、非聚簇索引(secondary index)
- 普通索引,比如给 name 建的索引
- 叶子节点只存储主键值(而不是整行数据)
- 查值时要先查索引树,再用主键去聚簇索引树中二次查找(叫回表)
所以这也解释了,为什么在设计表结构时,主键要选那种稳定、短小、唯一的字段!
再说说我后来是怎么“翻身”的
回到故事的起点。
我在第二轮面试前,把《高性能MySQL》里关于B+树的章节重新看了一遍,还看了几篇极客时间专栏 + 一段B站讲解动画。
我准备了一段自己的“索引小讲稿”,思路是这样:
- 从数据库为什么需要索引说起
- 引出“B树”和“B+树”的区别
- 讲明B+树的数据结构和查找原理
- 用场景解释为什么不是红黑树、不是哈希表
- 讲清楚聚簇索引和辅助索引的差异
- 最后补充一下页大小、树高等关键细节
结果——
面试官听完后说:“你这是把我问题当讲课了哈,但讲得很清楚,给个赞。”
那天我终于明白,搞懂原理很重要,但能讲明白更重要。
这道面试题,其实是一个数据库人的门槛题
最后,总结一句话:
B+树是数据库世界里的“数据高速公路”,每一个节点都像一个高速路口,合理组织才能让我们的SQL不迷路、跑得快。
如果你正在准备MySQL相关的面试,或者也被B树索引困扰过,不妨把这篇文章收藏下来,慢慢消化。
END
如果你喜欢这种“讲故事 + 技术干货”的风格,欢迎关注我呀,我是爱折腾数据库的“小米”,我们下期见~
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!