Skip to content

MySQL 三层 B+ 树能存多少数据? ​

  • 标签:后端、MySQL、数据库

🏛 业务架构师 ​

这个问题的价值不在数字本身,而在它是单表容量规划的经验锚点。

推算过程:InnoDB 页 16KB;非叶子页每个条目约 14 字节(8 字节主键 + 6 字节页指针),一页约 1170 个条目;叶子页按每行 1KB 算,一页放 16 行。三层 B+ 树容量 = 1170 × 1170 × 16 ≈ 2000 万行。

业务上怎么用这个数字:

  • 它是"树高从 3 变 4"的分水岭:四层树意味着每次查询可能多一次磁盘 IO,buffer pool 命中率下降的放大效应更明显。所以数据逼近 2000 万、且查询开始变慢时,就是启动治理的信号;
  • 2000 万不是铁律,是提醒:行更窄(比如日志表每行 200 字节,一页 80 行)时单表四五千万也流畅;行很宽则可能 800 万就吃力。要看树高、buffer pool 命中率、慢查询趋势三个指标,不要唯行数论;
  • 治理阶梯:先归档冷数据(交易表留 3 个月热数据)→ 读写分离 → 再分库分表。分库分表的迁移成本和跨片查询代价极高,能靠归档多扛一年就多扛一年。

我的习惯是给每张核心交易表定容量水位线(如 1500 万预警、2000 万动作),进季度容量评审。把推算变成机制,比背数字有用。

🏗 系统架构师 ​

这是道容量估算题,我按 InnoDB 默认 16KB 页推导:

估算假设:主键 bigint(8B)+ 页指针(6B)≈ 14B/项;行数据按 1KB 估。

  • 非叶子节点:16KB / 14B ≈ 1170 个索引项;
  • 叶子节点:16KB / 1KB ≈ 16 行/页;
  • 两层树(1 根 + 1170 叶):1170 × 16 ≈ 1.87 万行;
  • 三层树(1 + 1170 + 1170×1170):1170 × 1170 × 16 ≈ 2190 万行。

结论与工程意义:

  • 三层 B+ 树一次主键查询最多 3 次页访问,缓冲池热的话全内存命中,这就是"单表 2000 万"经验值的理论来源——超过后树高到 4 层,最坏多一次页 IO,缓存局部性也开始变差;
  • 但它不是硬上限:行更瘦(比如 200B/行)三层能放上亿;行宽、缓冲池大小、读写比例共同决定拐点。我用这个估算做分库分表的容量推演:预估 3 年数据量 × 行宽 → 是否破 3 层 → 决定单表保留多少、分多少片。

💻 全栈开发专家 ​

经典估算题,前提先说清楚:InnoDB 页 16KB,主键 bigint 8 字节,页指针 6 字节。

非叶子节点:16KB / (8B + 6B) ≈ 1170 个指针;叶子节点:假设每行 1KB(含行开销),16KB / 1KB = 16 行。

三层 B+ 树:

text
第 1 层:1 个根页          → 1170 个指针
第 2 层:1170 个页        → 1170 × 1170 ≈ 137 万个指针
第 3 层:137 万个叶子页   → × 16 行 ≈ 2190 万行

结论:约 2000 万行,只需要 3 次页 IO(根页常驻内存实际 2 次)。

工程引申(这是加分项):

  • 行越瘦,能存的越多:行 500B 时单叶子页 32 行,同结构可存 4000 万+。所以我做宽表拆分、冷热分离的理论依据就是控制行大小。
  • 这个数字也是"单表 2000 万左右考虑分表"经验值的出处——数据量再大,树变 4 层,每次查询多一次 IO。虽然 buffer pool 能掩盖大部分,但写入时的页分裂、锁竞争会先暴露。