单库单表与分库分表的优缺点:什么时候该分库分表?
一、先说结论
单库单表是默认选择,分库分表是数据量大到单库扛不住之后的无奈选择,而不是炫技手段。很多团队踩过的坑是:数据量根本不大,就提前分库分表,结果分布式事务、跨库查询、扩容迁移的复杂度反而把系统拖垮。
判断标准很简单:单库单表能满足,就别分;确实不满足了,再按需分。
二、单库单表:最简单也最容易被低估
单库单表就是所有数据放在一个数据库的一张表(或多张表)里,靠索引、缓存、读写分离来撑性能。
优点
| 优点 | 说明 |
|---|---|
| 事务简单可靠 | 本地事务 ACID 完整,不用考虑分布式事务 |
| 开发效率高 | 普通 SQL 随便写,join、子查询、分页都很自然 |
| 维护成本低 | 一个库一套备份迁移策略,DBA 轻松 |
| 一致性有保证 | 强一致,不存在数据同步延迟 |
| 上手门槛低 | 团队任何人都会用,排查问题也直观 |
缺点
| 缺点 | 说明 |
|---|---|
| 容量瓶颈 | 单机磁盘、内存有上限,海量数据存不下 |
| 性能瓶颈 | 数据量大了之后,索引变大、IO 变多,慢查询增多 |
| 连接数瓶颈 | 单库连接数有限,高并发下连接池被打满 |
| 单点风险 | 数据库挂了整个系统不可用(主从也只是缓解) |
| 无法横向扩展 | 加机器对单库没用,只能垂直加配置,有天花板 |
单库单表不是"差方案",它是性价比最高的方案。绝大多数中小系统,单库 + 索引 + 缓存 + 读写分离已经足够。
三、分库分表是什么
分库分表是"把一个大库/大表拆成多个小库/小表",主要有四种拆法:
| 拆分方式 | 做法 | 典型场景 |
|---|---|---|
| 垂直分库 | 按业务模块拆库,如订单库、用户库、商品库 | 业务模块之间天然隔离 |
| 垂直分表 | 把一张宽表拆成多张窄表,按字段拆分 | 大字段、热点字段分离 |
| 水平分库 | 同一张表的数据按规则散到多个库 | 数据量巨大,单库容量不够 |
| 水平分表 | 同一张表的数据按规则散到多张表 | 单表数据量过大,索引退化 |
其中水平分库分表是讨论最多的:按某个分片键(如 user_id、order_id)取模或按范围,把数据均匀散到多个库表的多个分片上。
四、分库分表的优点
1. 突破容量上限
单库容量有物理上限,分库后总容量 = 单库容量 × 库数量,理论上可以无限水平扩展。
2. 提升并发能力
请求被分散到多个库上,单库的连接数、CPU、IO 压力大幅下降,整体吞吐量可以线性提升。
3. 单表数据量可控
单表数据控制在千万级以内,索引效率高,慢查询减少。
4. 故障隔离
一个分片挂了,只影响该分片的数据,其他分片仍可用(当然业务上可能仍需兜底)。
5. 便于横向扩展
数据量再增长时,可以继续加机器加分片(需要迁移方案配合)。
五、分库分表的缺点(重点,容易被忽略)
1. 分布式事务
一个业务操作可能跨多个库,本地事务失效,需要引入 Seata、TCC、消息最终一致性等方案,复杂度直线上升。
2. 跨库 join 基本告别
数据分散在不同库,SQL join 不能用了,只能"多次查询 + 内存组装",代码变复杂、性能也打折。
3. 分布式 ID
自增主键在分片下会冲突,需要全局唯一 ID 方案:雪花算法(Snowflake)、号段模式(Leaf)、UUID 等。
4. 分页与排序困难
ORDER BY ... LIMIT 不再是单库排序,需要各分片分别查出再归并,深分页(翻到第 10000 页)代价极高。
5. 扩容迁移复杂
分片数量定死后再扩容,存量数据需要按新规则重新分布,往往是停机或双写迁移,风险高、成本大。
6. 运维成本上升
多库多表的备份、监控、慢日志、数据恢复都是成倍工作量。
7. 数据倾斜风险
分片键选得不好(热点用户、热点商品),数据分布不均,部分分片照样成为瓶颈。
8. 事务与一致性权衡
很多时候不得不接受"最终一致性",对业务代码和产品设计都是挑战。
六、单库单表 vs 分库分表:对比总结
| 维度 | 单库单表 | 分库分表 |
|---|---|---|
| 事务 | 强一致,简单 | 分布式事务,复杂 |
| 查询 | join/分页随便写 | 跨库查询受限,需组装 |
| 容量 | 有上限 | 可横向扩展 |
| 并发 | 单库上限 | 多库分摊 |
| 一致性 | 强一致 | 多为最终一致 |
| 开发成本 | 低 | 高 |
| 运维成本 | 低 | 高 |
| 适合场景 | 中小规模、业务初期 | 数据量/并发明确超标 |
七、什么时候该考虑分库分表
业界常见的参考阈值(不是硬标准,是经验值):
- 单表数据量超过 2000 万 ~ 5000 万,索引和查询性能明显退化;
- 单库连接数长期打满,连接池排队严重;
- 磁盘/IO 成为瓶颈,垂直加配置也扛不住;
- 数据增长趋势确定,未来 1~2 年必然突破单库上限。
更重要的前置顺序,先穷尽这些手段再考虑分库分表:
- 索引优化、SQL 优化、慢查询治理;
- 加缓存(Redis)挡热点读;
- 读写分离(主从复制);
- 垂直拆库拆表、冷热数据分离(归档历史数据);
- 以上都不行了,才上水平分库分表。
八、常见实现方案
| 方案 | 类型 | 特点 |
|---|---|---|
| Apache ShardingSphere(Sharding-JDBC / Sharding-Proxy) | 客户端 / 中间件 | 生态最全,Java 项目首选 |
| MyCat / MyCat2 | 中间件代理 | 对应用透明,兼容多语言 |
| Vitess | 中间件 | 大规模场景,K8s 生态友好 |
| 云数据库自带分片 | 托管服务 | 云厂商帮你做,成本高 |
九、总结
- 单库单表是默认方案:简单、可靠、成本低,适合绝大多数业务;
- 分库分表是"最后的手段":换来容量和并发,代价是事务、查询、运维全线复杂度上升;
- 动手分库分表之前,先做完索引、缓存、读写分离、垂直拆分这几步;
- 真要分,分片键选择是生死线,选错(热点倾斜)等于白分;
- 分库分表是架构演进的终点之一,不是起点。系统是慢慢长出来的,不是一步到位设计出来的。