【面试题】MySQL 三层 B+ 树能存多少数据?
这是一个经典的面试题,但实际估算需要考虑多个变量。下面我将详细拆解计算过程:
核心计算模型
MySQL B+树存储量 = 根节点扇出 × 中间节点扇出 × 叶子节点容量
关键假设(以InnoDB默认配置为例)
- 页大小:16KB(16384字节)
- 主键类型:BIGINT(8字节)
- 指针大小:6字节(InnoDB页指针)
- 行数据大小:1KB(1024字节) - 这是关键变量
- 页空间利用率:约70%(需扣除页头、页尾等元数据)
三层B+树结构
第1层:根节点(1个)
第2层:中间节点(fan_out个)
第3层:叶子节点(fan_out²个) ← 存储实际数据
详细计算步骤
1. 计算单个非叶子节点能存储的键值对数量(fan_out)
每个索引项大小 = 主键(8B) + 指针(6B) = 14B
可用空间 = 16KB × 70% = 11.2KB ≈ 11468字节
单个节点索引项数 = 11468 / 14 ≈ 819
即:每个非叶子节点可指向约819个子节点
2. 计算单个叶子节点能存储的数据行数
可用空间 = 16KB × 70% = 11.2KB
假设每行数据1KB → 每页约存储 11行
假设每行数据200字节 → 每页约存储 57行
假设每行数据800字节 → 每页约存储 14行
3. 三层B+树总容量计算
公式:总行数 = fan_out² × 每页行数
- 若每页11行:819² × 11 ≈ 730万行
- 若每页57行:819² × 57 ≈ 3800万行
- 若每页14行:819² × 14 ≈ 940万行
更精确的估算(考虑真实InnoDB结构)
实际InnoDB叶子节点存储的是完整数据行,需要考虑:
- 行格式开销(行头约23字节)
- 事务系统开销(MVCC的隐藏列:DB_TRX_ID 6B + DB_ROLL_PTR 7B)
- 可能的NULL位图、变长字段列表等
保守估算:
假设主键为BIGINT,每行额外开销约50字节:
- 行大小 = 数据(1024B) + 行开销(50B) = 1074B
- 每页行数 = (16384×70%) / 1074 ≈ 10行
- 总行数 = 819² × 10 ≈ 670万行
场景分析表
| 行大小 | 每页行数 | 三层B+树容量 | 四层B+树容量 |
|---|---|---|---|
| 200B(小记录) | ~57行 | 约3800万行 | 约310亿行 |
| 1KB(典型记录) | ~10行 | 约670万行 | 约55亿行 |
| 2KB(较大记录) | ~5行 | 约335万行 | 约27亿行 |
| 8KB(大记录) | ~1行 | 约67万行 | 约5.5亿行 |
重要说明
-
实际容量可能更大:
- 若使用INT主键(4字节),fan_out ≈ 1365,容量提升近3倍
- 若行记录更紧凑,每页存储行数更多
-
B+树层数增长:
- 当数据量超过三层容量时,B+树变为四层
- 四层B+树容量 = fan_out³ × 每页行数
- 对于1KB行,四层B+树可存储约 55亿行
-
聚簇索引 vs 二级索引:
- 上述计算针对聚簇索引(叶子节点存完整数据)
- 二级索引叶子节点存储主键值,容量会更大
结论
在典型的配置下(BIGINT主键、1KB行数据):
- 三层B+树大约能存储600万~1000万行数据
- 四层B+树可存储数十亿行数据
这也是为什么我们常说:
- 单表千万级别数据时,查询性能仍能保持良好(三层B+树)
- 数据量过亿时,可能需要考虑分库分表或优化索引设计
❤️ 如果你喜欢这篇文章,请点赞支持! 👍 同时欢迎关注我的博客,获取更多精彩内容!
本文来自博客园,作者:佛祖让我来巡山,转载请注明原文链接:https://www.cnblogs.com/sun-10387834/p/19388703

浙公网安备 33010602011771号