分库分表中,如何预估需要分多少个库?多少张表?
一则或许对你有用的小广告
欢迎加入小哈的星球,你将获得:专属的实战项目(4个项目都能学) / 1v1 提问 / 简历修改 / Java 学习路线 / 社群讨论 / 学习打卡 / 每月赠书
《Spring AI 项目实战(问答机器人、RAG 智能客服、联网搜索)》已完结,基于
Spring AI + Spring Boot 3.x + JDK 21...,查看介绍《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...,查看介绍;演示链接:http://116.62.199.48:7070/《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接:http://116.62.199.48/
新开坑项目:《从零手撸:秒杀系统高并发优化实战》 正在更新中...,查看介绍
截止目前,星球内专栏累计输出 150w+ 字,讲解图 5110+ 张,还在持续爆肝中.. 后续还会上新更多项目,已有 4700+ 小伙伴加入学习,欢迎点击围观
面试考察点
-
容量规划意识:面试官想知道你是不是只会用 ShardingSphere,而是真能根据数据量、并发量、未来增长算出合理的分片数。这是架构师的基本功。
-
实践经验:分多了浪费机器,分少了很快又要扩容(这个坑踩过的人都懂)。能不能给出具体数字、具体公式,决定你是 "会背八股" 还是 "真上过生产"。
-
权衡思维:分库分表数量是 2 的幂还是任意数?为什么?这是分库分表设计里最经典的权衡点,答得出来说明你考虑过扩容和数据迁移。
核心答案
先给一个可直接套用的思路:
- 分表数:按 "未来 3-5 年的数据总量 ÷ 单表推荐容量" 来估,单表建议控制在 500 万 ~ 1000 万行以内(保守一点 500 万,激进一点别超 2000 万)
- 分库数:按 "系统峰值并发 / 单库承载能力" 来估,MySQL 单机 QPS 一般按 3000 ~ 5000 估,保守按 1000 ~ 2000
- 结果约束:分库数 × 分表数最好是 2 的幂次方(方便后续扩容一倍时数据迁移最小化)
常见的生产配置组合:
| 配置 | 总表数 | 适用场景 |
|---|---|---|
| 2 库 × 8 表 | 16 张 | 中小系统,日均数据百万级 |
| 4 库 × 8 表 | 32 张 | 中型系统,千万级订单 |
| 8 库 × 16 表 | 128 张 | 大型电商订单系统 |
| 16 库 × 16 表 | 256 张 | 海量数据,3 年内预计破十亿 |
下面拆开细讲。
深度解析
一、分表数量怎么估:先算数据量
分表解决的是 "单表数据量大导致查询慢" 的问题。预估步骤:
- 估未来 3-5 年的数据总量
- 比如一个电商订单系统,日均订单 50 万,按 5 年算:50 万 × 365 × 5 ≈ 9 亿条
- 定单表容量上限
- B+ 树高度 3 层时,理论上能存千万级数据;但实际加上索引、慢查询风险,建议单表不超过 1000 万行
- 算分表数
- 9 亿 ÷ 1000 万 = 90,向上取 2 的幂 → 128 张表
上图是分表数的估算流程:从日均数据量推算出未来 3-5 年的总量,除以单表上限得到理论值,最后向上取 2 的幂次方得到最终分表数。
关键点:
- 单表 1000 万这个数不是死的。如果你索引建得好、查询都走索引、没有复杂聚合,单表 2000 万也能跑。但保守一点没坏处,扩容的代价比 "多分几张表" 大得多
- 必须预留 buffer:算出来是 90 张表,取 128 是给未来留余量;如果取 96(非 2 的幂),后面扩容会很痛苦
二、分库数量怎么估:再算并发量
分库解决的是 "单库写压力大、连接数不够、单机 IO 瓶颈" 的问题。预估步骤:
- 估系统峰值 QPS / TPS
- 比如订单系统峰值写 TPS 约 1 万
- 定单库承载上限
- MySQL 单实例 TPS 通常按 3000 ~ 5000 估,保守按 1500
- 算分库数
- 1 万 ÷ 1500 ≈ 6.7,向上取 2 的幂 → 8 个库
上图是分库数的估算流程:用峰值并发除以单库承载上限,再向上取 2 的幂次方。
为什么是 2 的幂:扩容时只需把每个库的数据对半切,迁移数据量最小。比如从 4 库扩到 8 库,原来 hash(userId) % 4 现在变成 hash(userId) % 8,只需要迁移一半数据。如果原来是 5 库扩到 10 库,几乎所有数据都要重分布——这个坑踩过的人都懂有多痛苦。
三、综合配置
把上面两步合到一起:
- 分表数 128 张
- 分库数 8 个
- 每个库 128 ÷ 8 = 16 张表
最终配置:8 库 × 16 表 = 128 张表。这是比较经典的中大型系统配置。
库表比例的考量:
| 比例 | 特点 | 适用场景 |
|---|---|---|
| 库少表多(2 库 × 64 表) | 单机压力大,但运维简单 | 数据量大但并发不高 |
| 库多表少(16 库 × 4 表) | 单机压力小,但运维成本高 | 并发高但单表数据量可控 |
| 库表均衡(8 库 × 16 表) | 综合最常用 | 大多数电商、金融场景 |
四、几个容易踩的坑
- 只算现在不算未来:分库分表一旦上线,扩容够你喝一壶。一定要按 3-5 年后的数据量来估,宁可多分几张
- 单表太小也算问题:有些人一上来就 1024 张表,结果每张表就几万条数据,B+ 树两层都不到,反而增加了路由开销和跨库聚合的复杂度
- 忽略跨库聚合成本:分得越细,JOIN、count、分页查询越难做。这点在订单、报表类业务上特别明显
- 路由字段选错:用
userId还是orderId做分片键,影响后续所有查询能不能走单库。这个不是这次的重点,但要提一句
面试高频追问
-
追问一:为什么分库分表数量必须是 2 的幂?
- 核心原因是为了扩容时数据迁移最小化。从 2ⁿ 扩到 2ⁿ⁺¹ 时,每个分片只需要拆一半出去,迁移量正好是 50%。非 2 的幂扩容几乎要全量重分布。
-
追问二:分库分表后,怎么解决跨库分页查询?
- 几种思路:① 全局表 / 广播表(小数据量);② ES 同步做查询侧;③ 应用层合并 + 二次查询;④ 用 TiDB 等 NewSQL 数据库。生产里一般用 ES 做查询侧。
-
追问三:如果数据量增长超过预期怎么办?
- 几个方向:① 加倍扩容(4 库 → 8 库,数据迁移一半);② 读写分离分摊压力;③ 冷热数据分离(历史数据归档到 HBase 或 OSS);④ 业务垂直拆分。
常见面试变体
- "分库分表怎么选分片键?"
- "分库分表后主键 ID 怎么生成?"(答雪花算法、号段模式)
- "分库分表和读写分离先做哪个?"
- "如果业务一开始数据量不大,要不要预先分库分表?"(答案:不要,过早优化是万恶之源,先单库做好索引和分区)
记忆口诀
两步走、两约束:
- 第一步:量除量——总数据量 ÷ 单表上限 = 分表数
- 第二步:流除流——峰值并发 ÷ 单库上限 = 分库数
- 约束一:结果向上取 2 的幂
- 约束二:预留 3-5 年 buffer
总结
分库分表数量预估不是玄学,是有公式的:数据量决定分表数,并发量决定分库数,结果都向上取 2 的幂。把 "未来 3-5 年" 这个时间窗口和 "单表 1000 万行、单库 TPS 保守按 1500" 这两个经验值记住,面试答得出来,生产也用得上。千万别凭感觉分,不然上线半年就得扩容,到时候你就知道什么叫 "血泪教训" 了。
