P22 单表最多数据量需要分表
面试题:单表数据量达到多少就应该分表?为什么?
核心观点
没有绝对的阈值(500 万、1000 万、2000 万都是经验值),关键看是否出现性能劣化,通常关注 B+ 树层数和单表过大带来的问题。
1. 为什么数据量大性能会下降
① B+ 树层数
InnoDB 主键索引是 B+ 树,非叶子节点存索引、叶子节点存数据。假设:
- 每行 1KB,每个数据页 16KB(一页约 16 行数据);
- 非叶子节点每页能存约 1000 个主键(8 字节主键 + 6 字节指针);
| 层数 | 能容纳行数 |
|---|---|
| 2 层 | 约 1000 × 16 ≈ 1.6 万行 |
| 3 层 | 约 1000 × 1000 × 16 ≈ 1600 万行 |
| 4 层 | 约 16 亿行 |
所以 3 层 B+ 树覆盖千万级数据,几百万到一两千万行通常还在合理范围;超过后树变 4 层,每次查询多一次磁盘 IO,性能开始明显劣化。
② 其他劣化因素
- 索引变大,内存(Buffer Pool)放不下,随机 IO 变多;
- 单表过大导致备份、DDL(加索引/加字段)时间很长,影响线上;
- 大表的锁竞争、死锁概率、脏页刷盘压力增加;
- 历史数据与热数据混在一起,缓存命中率下降。
2. 常见经验值
- 500 万 ~ 2000 万:看字段宽度和访问模式,多数业务在这个范围就开始考虑分表;
- 更科学的判断:单表行数 × 单行大小 ≈ 几个 GB 时开始关注;或直接压测观察查询/写入退化曲线;
- 数据只有几十万但字段巨大(如多个 TEXT),也可能需要拆表。
3. 分表前先做的事
不要一上来就分表,先排除这些:
- 索引是否合理(有没有走全表扫描);
- 是否需要归档/冷热分离(历史数据挪走,单表立刻瘦身);
- 是否可以不只分表而是分区表(按时间分区,对业务透明);
- 缓存是否承担了热点读。
4. 真要分表的注意点
- 分表键选择(按业务主键/用户 ID 均匀分布);
- 分表后查询要走分表键,否则全表扫所有分片;
- 配合分库(分散 IO 和连接数);
- 分布式 ID、跨分片聚合、分页、事务问题都要重新设计。
一句话总结
单表行数在百万到千万级(约 3 层 B+ 树、几个 GB)时开始评估分表;没有固定数字,以"查询/写入是否劣化 + 运维是否吃力"为准,且优先用索引优化、归档、分区表等手段,分表是最后手段。