分库分表是解决单机数据库性能瓶颈、支撑海量数据和高并发访问的核心架构手段。下面从「为什么做」「是什么」「怎么做」「常见问题」四个层面系统说明。
一、为什么要分库分表?
当业务发展到一定阶段,单机 MySQL / PostgreSQL 等关系型数据库往往会遇到以下问题:
| 问题 | 表现 |
|---|---|
| 数据量过大 | 单表几千万~上亿行,B+树层级变深,查询变慢 |
| 写入瓶颈 | 单点写入 TPS 上限明显,主库 CPU / IO 打满 |
| 连接数不足 | 应用扩容后,数据库连接池耗尽 |
| 锁竞争严重 | 大表 DML 导致行锁 / 表锁冲突 |
| 可用性风险 | 所有数据集中在一套库,故障影响面大 |
👉 目标:把数据拆到多个库、多个表中,降低单点压力,提高性能和扩展性。
二、什么是分库分表?
1️⃣ 分库(Sharding / Database Split)
把一个逻辑数据库拆成多个物理数据库实例:
- 不同库部署在不同机器上
- 每个库只存一部分数据
- 库之间通常不做 JOIN
常见方式:
- 垂直分库
- 水平分库
2️⃣ 分表(Table Sharding)
把一个大表拆成多个结构相同的子表:
- 每张表字段一致
- 数据按规则分散到不同表
- 查询时需要路由到正确的表
常见方式:
- 垂直分表
- 水平分表
三、四种常见拆分方式
1️⃣ 垂直分库(按业务拆分)
按业务模块拆分数据库
order_db
user_db
product_db
payment_db
✅ 优点:
- 业务解耦
- 降低单库复杂度
- 便于独立扩容和维护
❌ 缺点:
- 跨库 JOIN 困难
- 分布式事务问题
📌 典型场景:微服务架构
2️⃣ 垂直分表(按字段冷热拆分)
将一张表的字段拆分到多张表
user_base(id, username, password)
user_profile(user_id, nickname, avatar)
user_ext(user_id, bio, settings)
✅ 优点:
- 减少单行大小
- 热点字段访问更快
- 提升缓冲命中率
📌 典型场景:
- 用户表、商品表
- TEXT / JSON / BLOB 字段单独拆
3️⃣ 水平分表(单库内拆分)
表结构不变,数据行拆分
order_00
order_01
order_02
...
order_31
✅ 优点:
- 降低单表数据量
- 查询性能提升
❌ 缺点:
- 需要路由逻辑
- 跨表查询复杂
📌 常用于:单库还能撑住,但表太大
4️⃣ 水平分库分表(最彻底)
既分库又分表(真正的 Sharding)
db_0.order_00 ~ order_31
db_1.order_00 ~ order_31
db_2.order_00 ~ order_31
✅ 优点:
- 突破单机容量和性能上限
- 支持超大规模数据
❌ 缺点:
- 架构复杂
- 运维成本高
- 分布式一致性挑战
📌 典型场景:
- 电商订单
- 支付流水
- 日志 / 轨迹数据
四、分片键(Shard Key)怎么选?
这是分库分表成败的关键
✅ 好的分片键特征
- 高频查询条件
- 数据分布均匀
- 不可变(尽量)
- 基数大
❌ 不好的分片键
- 状态字段(status)
- 性别、类型等低基数字段
- 随机 UUID(无业务意义)
常见示例
| 业务 | 分片键 |
|---|---|
| 订单 | order_id / user_id |
| 用户 | user_id |
| 交易流水 | trans_id |
| 日志 | timestamp + hash |
⚠️ 如果按 user_id 分片,但经常按 order_id 查,就需要映射表或基因法。
五、分片算法
| 算法 | 说明 |
|---|---|
| 取模分片 | shard = id % N(简单但不利于扩容) |
| 哈希分片 | hash(id) % N(分布更均匀) |
| 范围分片 | 按时间 / ID 区间(易产生热点) |
| 一致性哈希 | 扩容迁移数据少(中间件常用) |
| 基因法 | 分片键中嵌入分片信息 |
六、典型实现方案
1️⃣ 客户端分片(应用层)
- 应用自己算路由
- 直连多个数据源
✅ 性能好
❌ 代码侵入强
2️⃣ 中间件分片(主流)
| 中间件 | 特点 |
|---|---|
| ShardingSphere | Apache 顶级项目,功能完善 |
| MyCat | 老牌,偏 proxy |
| Vitess | YouTube 开源,K8s 友好 |
| TiDB | NewSQL,自动分片 |
✅ 对业务透明
✅ 维护成本低
❌ 有一定性能损耗
3️⃣ 云厂商托管
- 阿里云 DRDS / PolarDB-X
- AWS Aurora + Sharding
- 腾讯云 TDSQL
七、分库分表带来的挑战
| 问题 | 说明 |
|---|---|
| 分布式事务 | XA / TCC / SAGA |
| 全局唯一 ID | Snowflake / Leaf / UUID |
| 跨分片查询 | 聚合、排序、分页困难 |
| 扩容 | 数据迁移成本高 |
| 运维复杂度 | 监控、备份、DDL |
📌 一句话:能不分就不分,分了就要接受复杂度。
八、什么时候该分库分表?
✅ 建议考虑的信号
- 单表 > 1000 万行(MySQL)
- QPS > 5000~10000
- 单机磁盘 > 1TB
- 主库写入成为瓶颈
- 业务持续增长预期明确
❌ 不建议过早分库分表
- 数据量小
- 访问模式不稳定
- 团队缺乏分布式经验
九、一句话总结
分库分表本质是用复杂度换扩展性:
- 垂直拆分解决“耦合与臃肿”
- 水平拆分解决“容量与性能”
- 真正落地时,分片键设计和中间件选型比拆本身更重要