惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Announcements
Recent Announcements
人人都是产品经理
人人都是产品经理
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
GbyAI
GbyAI
博客园 - 司徒正美
美团技术团队
Vercel News
Vercel News
IT之家
IT之家
U
Unit 42
Y
Y Combinator Blog
罗磊的独立博客
Microsoft Security Blog
Microsoft Security Blog
MongoDB | Blog
MongoDB | Blog
Jina AI
Jina AI
V
Visual Studio Blog
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
MyScale Blog
MyScale Blog
博客园 - 叶小钗
A
About on SuperTechFans
WordPress大学
WordPress大学
Hugging Face - Blog
Hugging Face - Blog
B
Blog RSS Feed

博客园 - 野鹤闲人

ubantu 耳机调试 keepalived+nginx msg广播到同一个group中,怎么保证所有consumer都消费到,Rocketmq和rabbitmq 分别是怎么做的 mysql优化语句时,关注哪几列 extra要关注吗 CountDownLatch/CyclicBarrier 区别 机器缩容要注意哪些问题 IO模型有哪几种 ConcurrentSkipListMap 并发安全实现 TreeMap hive 小文件优化 redis缓存雪崩问题解决 CAS原理 docker的常用命令 k8s的常用组件,和命令 如何保证rabbitmq或kafka 消息不丢失,从生产到消费端全过程 java排查工具 JAVA 强软弱虚引用 git Spring 事务失效
mysql B+树 如果有3层,能保存多少数据
野鹤闲人 · 2026-01-05 · via 博客园 - 野鹤闲人

MySQL 中 3 层的 B + 树结构最多能存储多少条数据,这个问题需要结合 B + 树的结构特点和页大小来计算。

一、先明确核心前提

MySQL 的 InnoDB 存储引擎中,B + 树的每个节点对应一个数据页(默认大小 16KB=16384 字节),我们需要先确定:

  1. 非叶子节点:只存储「索引键 + 子节点指针」,不存数据;
  2. 叶子节点:存储「索引键 + 数据行指针 / 整行数据」(主键索引叶子节点存整行,二级索引存主键);
  3. 指针大小:InnoDB 中指针固定为6 字节;
  4. 索引键大小:以最常见的BIGINT主键(8 字节)为例(如果是 INT 则 4 字节,可替换计算)。

二、分步计算(以 BIGINT 主键为例)

1. 计算非叶子节点的子节点数(扇出数)

非叶子节点的每个条目 = 索引键(8 字节) + 子节点指针(6 字节) = 14 字节。
一个 16KB 的页,扣除页头 / 页尾的固定开销(约 100 字节),可用空间约 16284 字节。

单页可存储的条目数 = 16284 ÷ 14 ≈ 1163(向下取整,保证不超页大小)。
即:每个非叶子节点最多指向 1163 个子节点(扇出数 = 1163)。

2. 3 层 B + 树的层级结构拆解

3 层 B + 树的结构是:「根节点(第 1 层)」→「中间节点(第 2 层)」→「叶子节点(第 3 层)」。

  • 第 1 层(根节点):1 个节点,最多指向 1163 个第 2 层节点;
  • 第 2 层(中间节点):最多 1163 个节点,每个节点又指向 1163 个第 3 层叶子节点;
  • 第 3 层(叶子节点):最多 1163×1163 = 1352569 个节点。

3. 计算叶子节点的单页数据行数

叶子节点存储整行数据(主键索引),假设每行数据大小为 1KB(实际可根据业务调整,比如 512 字节、2KB):
单叶子页可存行数 = 16KB ÷ 1KB = 16 行(若行更小,比如 512 字节,则单页存 32 行)。

4. 最终总数据量计算

总数据行数 = 叶子节点数 × 单叶子页行数
= 1163×1163 × 16
≈ 1163² ×16 = 1352569 ×16 ≈ 21641104 行(约 2164 万行)。

三、不同条件下的调整

如果调整参数,结果会变化,举 2 个常见例子:

调整条件扇出数叶子单页行数3 层 B + 树总行数
主键为 INT(4 字节) ~1809 16 ≈1809²×16≈5227 万
行大小为 512 字节 1163 32 ≈4328 万
页大小改为 32KB ~2327 32 ≈2327²×32≈17298 万

总结

  1. 3 层 B + 树的存储量核心取决于非叶子节点的扇出数(由索引键大小、页大小决定)和叶子节点单页行数(由行大小决定);
  2. 以默认 16KB 页、BIGINT 主键、1KB 行大小为例,3 层 B + 树约能存2164 万行;
  3. 实际场景中,因页内开销、行大小差异,实际存储量会略低于理论值,但量级基本一致(千万级)。

-------------------------

这个 100 字节的固定开销,是InnoDB 数据页结构中 “页头 + 页尾” 的通用估算值,并非精确值,本质是对页元数据占用空间的简化描述。

一、先看 InnoDB 数据页的完整结构

InnoDB 的 16KB 数据页,整体分为 7 个部分,其中页头(File Header)、页尾(File Trailer) 是所有类型数据页(不管是叶子节点还是非叶子节点)都必须有的固定结构,再加上少量其他固定元数据,共同构成了这约 100 字节的开销。

数据页结构大小(字节)作用
File Header(页头) 38 存储页的通用信息:页类型(叶子 / 非叶子)、上一页 / 下一页指针、页编号、创建时间等
Page Header 56(非叶子节点)/ 12(叶子节点) 存储当前页的特有信息:如非叶子节点的指针数量、叶子节点的记录数等
Infimum/Supermum 26 页内的最小 / 最大虚拟记录,用于界定记录范围,是固定存在的
User Records 可变 实际存储的用户数据(叶子节点)或索引 + 指针(非叶子节点)
Free Space 可变 页内的空闲空间
Page Directory 可变 页内记录的目录项,加速记录查找
File Trailer(页尾) 8 存储页的校验和、事务 ID 等,用于校验页的完整性(防止数据损坏)

二、“约 100 字节” 的估算逻辑

我们以非叶子节点(计算扇出数时用的就是非叶子节点)为例,把固定必有的元数据加起来:

  1. File Header(38 字节) + File Trailer(8 字节) = 46 字节;
  2. 加上 Page Header(非叶子节点 56 字节)的核心固定部分;
  3. 再加上 Infimum/Supermum 的基础开销(26 字节)中的一小部分;

把这些核心固定元数据相加,大概在 90-120 字节 之间,为了计算方便,就统一估算为 100 字节。

三、为什么不用精确值?

  1. 不同页类型的开销有差异:叶子节点的 Page Header 只有 12 字节,比非叶子节点的 56 字节小很多,精确计算会增加复杂度;
  2. 相对 16KB 的页大小,100 字节的影响极小:16KB=16384 字节,100 字节仅占 0.6% 左右,对扇出数的计算结果(比如 1163)影响微乎其微,简化估算完全不影响量级结论;
  3. InnoDB 版本会有微调:不同 MySQL 版本的页结构可能有小改动,元数据大小会有 ±10 字节的波动,用 “约 100 字节” 是行业内的通用简化表述。

总结

  1. 100 字节是页头、页尾及核心元数据的估算总和,不是精确值;
  2. 这个估算的目的是扣除固定开销,计算页的可用空间,方便推导扇出数;
  3. 因为占比极低,无论精确值是 90 还是 120,都不会改变 “3 层 B + 树支撑千万级数据” 的核心结论。