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次磁盘,速度会慢很多。


相关推荐
天天喝旺仔9 小时前
MySQL 索引原理与慢查询优化实战:从 B+ 树到执行计划调优
数据库·sql·mysql·性能优化
m0_6464299711 小时前
MySQL 初始化 SQL 中文乱码问题总结
数据库·sql·mysql
实战派K8S&DB11 小时前
TDSQL 核心模块与进程体系
运维·数据库·分布式·sql·mysql
Lost_the_wind11 小时前
MySQL 学习笔记三
笔记·学习·mysql
腾科IT教育12 小时前
Oracle OCP和MySQL OCP怎么选?方向对比指南
mysql·oracle·ocp·oracle ocp·ocp怎么选·mysql ocp
用户4603812919413 小时前
别人都 commit 了,为什么我的 select 还是旧值?图解 MySQL MVCC
mysql
毕业设计70315 小时前
(免费领源码)django空气净化器销售系统09218- java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
python·scrapy·mysql·pycharm·django·flask·pandas
CJi0NG17 小时前
【自用】MySQL-事务
数据库·mysql
VX_bysjlw98517 小时前
数码设备销售网站设计与实现39138-计算机毕设原创(免费领源码+带部署教程)
java·vue.js·spring boot·mysql·tomcat·mybatis·idea
PHP实战开发录17 小时前
MySQL数字排序为什么乱
数据库·mysql·php