MySqL 的 B+树、 叶子节点、非叶子节点

文章目录

叶子节点、非叶子节点

B+ 树,本质就是一棵从上到下分层的树状目录结构,一共就两类节点:

  • 上面所有层 → 非叶子节点(目录层)
  • 最底下一层 → 叶子节点(数据层)

一、非叶子节点:只当"指路牌",不存真实数据

是什么

就是树的中间目录层

最顶部的叫根节点,中间的叫分支节点,它们统一都叫非叶子节点。

里面存什么

只存两样东西:

  1. 索引键:比如主键id的值(10、20、30...)
  2. 下一层节点的地址:相当于"页码",告诉你下一层的节点在磁盘的哪个位置

它里面半条真实的行数据都没有,比如,你查id=15的员工,非叶子节点里不会存这个员工的姓名、年龄这些信息,只会告诉你"15在第二个叶子节点里"。

作用:只做导航

就像字典的拼音目录、部首目录,它的唯一作用就是帮你快速定位到"数据在哪一页",本身不提供任何完整内容。

比如,你查 "张" 字:

  1. 先看声母目录,找到 zh 对应的页码范围
  2. 再翻到韵母目录,找到 ang 对应的具体页码
  3. 最后才翻到正文页
    前面两步的目录,就全是非叶子节点,只指路,不存解释。

二、叶子节点:真正存数据的地方

是什么

是 B+树 最底下的一层,也是 查询的最终目的地。

里面存什么

在 InnoDB 的聚簇索引里:

  • 叶子节点存的是完整的一行数据(id、name、age、phone、email ... 所有字段的真实值)

这就是那句话的意思:所有数据都存在叶子节点。你要的任何真实业务数据,只能在最底层的叶子节点里找到,上面的目录层里一概没有。

额外特点:有序且双向相连

所有叶子节点,按索引值从小到大排好序,并且,相邻的叶子节点之间用 "双向链表" 连起来。

好处就是:一旦你找到了起点,比如 id>100的第一条数据,顺着链表往后挨个走,就能把所有符合范围的数据都取出来,天然支持范围查询和排序。


三、用一张文字结构图直观感受

B+树是 多叉树(也叫多路搜索树) ,不是二叉树。

一个节点可以存很多个索引键 ,不是只能存1个。

例子里只画了2个id,是为了画图方便做的极度简化,实际一个节点里能存上千个id。

复制代码
                  【根节点(非叶子)】
                  id: 20   id: 50
                   /            \
          【分支节点】        【分支节点】(都是非叶子)
         id:10 id:15        id:30 id:40
         /       \          /       \
【叶子1】 ↔ 【叶子2】 ↔ 【叶子3】 ↔ 【叶子4】(最底层,存完整数据)
id:1-9    id:10-19   id:20-29   id:30-49
存完整行   存完整行    存完整行    存完整行

你查 WHERE id = 17 的过程:

  1. 先到根节点:17 < 20,走左边分支
  2. 到分支节点:15 < 17 < 20,走第二个叶子节点
  3. 到叶子2节点,找到id=17的完整行数据,查询结束

上面两步走的都是非叶子节点,纯指路;最后一步到叶子节点,才拿到真实数据。


四、为什么这么设计,就能"IO少、速度快"?

这就是之前说的 "矮胖结构" 的核心原因:

  • 非叶子节点不存数据,只存 键值 + 地址,体积非常小。MySQL一页默认16KB,一页就能存上千个主键值。
  • 一层就能覆盖上千个范围,两层就能覆盖上百万条数据,三层就能覆盖上亿条数据。
  • 所以百万级数据,查询最多也就读3次磁盘(根节点 → 分支节点 → 叶子节点),速度极快。

如果非叶子节点也存数据,那一页存不了几个键,树就会变得又高又瘦,查一条数据要读十几次磁盘,就慢了。




解析 B+ 树、二叉查找树

B+树是 多叉树(也叫多路搜索树) ,不是二叉树。

一个节点可以存很多个索引键,不是只能存1个。


一、先纠正误区:不是所有树都是"一个节点存一个值"

你会有 "一个节点存一个id" 的印象,大概率是之前见过二叉查找树

  • 二叉树:每个节点只能存1个值,最多分左右两个分叉。
  • B+树:每个节点可以存N个值,分出N+1个分叉,所以叫"多叉树"。

这也是B+树能做到"矮胖"、IO次数少的根本原因。


二、一个节点里到底存了什么?

我们拿非叶子节点举例,它的内部结构是:「索引键」和「子节点指针」交替排列

规则很简单:

  • 如果一个节点里有 N 个索引键 ,就会对应 N+1 个子节点指针
  • 每个指针,负责指向一个数值区间。

就拿你图里的根节点举例:

复制代码
根节点里的值:id: 20    id: 50
对应指针:    ↙        ↓        ↘
           指针1     指针2      指针3

三个指针对应三个区间:

  1. 指针1:所有 id < 20 的数据,去左边的子节点找
  2. 指针2:所有 20 ≤ id < 50 的数据,去中间的子节点找
  3. 指针3:所有 id ≥ 50 的数据,去右边的子节点找

上面那个图里只画了两个分支,是因为画图时把最右边大于50的部分省略了,属于简化示意。


为什么要这么设计?

一页目录能放下几十个分界标记,就能指引几十页正文,目录本身就不用做太厚。对应到数据库:

  • 一个节点就是MySQL的一页数据(默认16KB),只存索引键+指针,能放下上千个id。
  • 一层就能划分上千个区间,两层就能覆盖上百万条数据,三层就能覆盖上亿条。
  • 树的高度只有3-4层,查一条数据最多读3次磁盘,这就是B+树快的核心。

如果一个节点只能存1个id(二叉树),那百万条数据树高就有20层,查一次要读20次磁盘,速度会慢很多。


相关推荐
夜雪一千2 小时前
MySQL查询条件的顺序是否影响查询效率
数据库·mysql
凤山老林3 小时前
MySQL“读已提交“并非万能药:深度解析RC隔离级别的盲区与适用边界
数据库·mysql
garuda herb3 小时前
生成专题页Blog--建立并返回 MySQL 数据库连接
python·mysql
奶糖 肥晨3 小时前
DBeaver 安装与 MySQL 连接配置教程
数据库·mysql
万亿少女的梦1684 小时前
基于Spring Boot、Java与MySQL的网络订餐系统设计与实现
java·spring boot·mysql·系统设计·网络订餐
Database_Cool_6 小时前
阿里云 RDS MySQL 降本增效实战:从规格选型到成本优化,月成本降低64%全攻略
mysql·阿里云·云计算
Cloud云卷云舒15 小时前
云卷云舒:从Oracle/MySQL迁移到HaishanDB:迁移评估工具核心技术拆解
mysql·oracle·ai-native·haishandb·信创数据库替换
用户713335851562418 小时前
MySQL - 事务、redo/undo 日志与 MVCC
mysql
用户713335851562419 小时前
MySQL - InnoDB 的 Buffer Pool
mysql