贝利信息

SQL B+ 树索引的真实工作方式

日期:2026-01-18 00:00 / 作者:冷漠man
B+树索引高效源于叶子节点有序链表、非叶节点纯导航及单次I/O覆盖多键;聚簇索引叶子存整行,二级索引叶子存字段值+主键值,回表增加I/O;覆盖索引可避免回表;非叶节点仅存路由键和页号,键越小树高越低;范围查询依赖叶子双向链表实现顺序I/O;自增主键减少分裂,UUID主键易致碎片。

SQL 中的 B+ 树索引不是“按关键字快速跳转”的黑盒,而是一套严格依赖数据物理组织和树结构特性的查找机制——它的高效,来自叶子节点的有序链表、非叶节点的纯导航作用,以及一次磁盘 I/O 尽可能覆盖更多键值的设计。

叶子节点存全量数据(聚簇索引)或主键(二级索引)

在 InnoDB 中,主键索引(聚簇索引)的叶子节点直接存放完整的行记录,数据按主键顺序物理存储;而普通字段上的二级索引,叶子节点只存该字段值 + 对应的主键值(不是指针,是实际主键值),查到后再回表——这意味着二级索引范围扫描时,若需大量非索引列,I/O 成本可能远超预期。

非叶节点只存“路由键”和子页地址,不存真实数据

B+ 树的非叶节点(包括根和中间层)仅保存用于导航的“分割键”(split key)和对应子节点页号。这些键是子树中最小(或最大)键的副本,仅作分流用,本身不关联任何用户数据。因此,非叶节点越小,树的高度就越低,查询路径就越短

范围查询靠叶子节点的双向链表,不是反复回溯父节点

一旦定位到范围起点的叶子页(比如 WHERE id BETWEEN 1000 AND 2000),B+ 树不再向上找父节点再下探,而是直接利用叶子节点之间通过双向链表相连的特性,顺序遍历后续叶子页——这使得范围扫描接近顺序 I/O,远快于等值查询的多次随机 I/O。

插入/更新会触发页分裂,但分裂策略尽量保持右饱和

B+ 树插入新键时,若目标叶子页已满,就会分裂:原页前半数据保留,后半数据移入新页,并在父节点插入新键指向新页。InnoDB 默认采用“保守分裂”(约 1/2 分裂),且优先向右分裂——这使主键自增场景下,新记录总追加到最右叶子页,极少触发分裂,写性能极高。