面试中解释 B+ 树,如果只说"树比较矮",还没有说明数据库为什么需要这样的组织方式。关键是数据库按页管理数据,查询要同时考虑点查、范围扫描和写入维护。
从页内导航理解分叉
B+ 树的内部节点主要保存导航所需的信息,叶子节点保存相应的数据记录或索引记录。一个页能容纳较多导航项,便可以指向更多子页,减少访问路径的层数。
这并不意味着一次查询固定产生几次磁盘 I/O。上层页可能已经在缓冲池里,叶子页也可能命中缓存。树高描述结构,实际耗时还受缓存、数据量与访问模式影响。
范围查找为什么适合
假设查询某段时间内的订单,索引先定位到范围起点,再沿叶子层扫描后续记录,直到超过终点。这样能够利用键的顺序组织,减少重新从根开始寻找每条记录的工作。
叶子有顺序联系,不代表磁盘空间完全连续。分页、分裂和维护都会影响实际布局。查询是否高效,仍需要看扫描范围和符合条件的数据量。
哈希结构擅长按键做等值定位,却不能仅靠哈希值自然表达"大于某个日期"的有序范围。二叉平衡树也能维护顺序,但数据库的页结构更适合较大的分叉数。
在 InnoDB 里区分两种叶子记录
InnoDB 聚簇索引的叶子保存行数据,通常由主键组织。二级索引记录则包含索引列和主键列,查询需要额外列时,可以根据主键再访问聚簇索引,这个过程通常叫回表。MySQL 官方索引说明明确描述了这一区别。
假设表有订单 id、创建时间和金额,二级索引按创建时间组织。按日期筛选,再取金额,可能需要从二级索引得到主键,再读取行数据。
如果查询所需的列已经由索引覆盖,就有机会减少为补充列值而访问聚簇索引的工作。不过,事务可见性等因素仍可能影响实际访问,不能把覆盖索引理解为任何情况下都绝不碰行数据。
| 查询关注点 | 需要观察的内容 |
|---|---|
| 范围是否过大 | 扫描了多少索引记录 |
| 是否需要额外列 | 是否发生额外的聚簇索引访问 |
| 主键是否过长 | 二级索引占用是否变大 |
| 写入是否频繁 | 额外索引带来的维护成本 |
索引越多也会增加成本
二级索引包含主键,因此很长的主键会增加二级索引记录的空间。为了覆盖一个查询,把很多大字段加入索引,也会增加存储与写入维护成本。
建索引前先确认真实查询的条件、排序与返回列。使用有代表性的数据查看执行计划、实际扫描和耗时,再和写入成本一起判断。只用几条测试数据,通常很难看到范围变大或回表增加后的区别。
B+ 树提供了适合页存储和有序查询的结构,具体索引仍要围绕业务访问设计。把叶子存什么、查询经过哪里说清楚,回表与覆盖索引就能顺着同一条路径理解。
我是程序员Sunday,本文相关的完整解析收录在 sunday面试指南,可继续阅读《MySQL 索引为什么用 B+ 树?与 B 树、哈希索引有什么区别?》。