什么是分库?分表?分库分表?
结论:分表把一张大表按规则拆成多张物理小表,解决单表数据量与索引深度问题;分库把数据拆到多个数据库实例,解决单机 CPU、IO、连接数上限。两者叠加就是「分库分表(Sharding)」。垂直拆分按业务或字段切,水平拆分按行切;先定位瓶颈再拆,能靠索引、归档、读写分离解决的,不要上分片。
一、四种拆分方式
| 方式 | 拆分依据 | 典型动作 | 解决的问题 | 主要代价 |
|---|---|---|---|---|
| 垂直分库 | 业务域 | 订单库、用户库、商品库独立部署 | 单库资源争抢、故障隔离 | 跨库事务、跨库 JOIN |
| 垂直分表 | 字段冷热 | 订单主表 + 订单详情表(大字段) | 单行过大、IO 放大 | 多一次关联查询 |
| 水平分表 | 行 | t_order 拆成 t_order_0..15 | 单表行数、B+ 树层高 | 路由、分页、聚合 |
| 水平分库 | 行 | 同规则落到 ds0..ds3 | 单实例写入、连接数瓶颈 | 分布式事务、扩容迁移 |
垂直:按业务/字段切 水平:按行切
┌──────────────┐ ┌──────────┐ ┌────────────────────────┐
│ 单体库 │ │ 订单库 │ │ t_order(1 亿行) │
│ 用户/订单/商品 │ ───► │ 用户库 │ │ ├─ t_order_0 625 万 │
└──────────────┘ │ 商品库 │ │ ├─ t_order_1 625 万 │
└──────────┘ │ └─ ... │
└────────────────────────┘
垂直拆分的产物是「不同库、不同表结构」;水平拆分的产物是「同结构的多张表」,因此只有水平拆分才需要分片键(Sharding Key)与路由算法。
二、什么时候才该拆
行业里常引用的经验阈值:单表行数超过 500 万行,或单表容量超过 2 GB,就应考虑分表。这是经验值而非硬指标——行宽 200 字节和 2 KB 的表,同样 500 万行完全是两个量级。
判定顺序建议:
- 先看慢查询:索引缺失、回表、深分页往往能解释大部分性能问题。
- 再看容量:单表超过阈值且无法归档,才进入分表候选。
- 最后看写入:单库写入 QPS 打满、连接数耗尽时,才需要分库。
三、配置样例
ShardingSphere 5.x 的逻辑表配置,把 t_order 映射到两个库各两张表:
spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://10.0.0.11:3306/order_db
username: app
password: ${ORDER_DB_PWD}
ds1:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://10.0.0.12:3306/order_db
username: app
password: ${ORDER_DB_PWD}
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..1}
database-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: db_mod
table-strategy:
standard:
sharding-column: order_id
sharding-algorithm-name: tbl_mod
sharding-algorithms:
db_mod:
type: MOD
props:
sharding-count: 2
tbl_mod:
type: MOD
props:
sharding-count: 2
SQL 侧看起来没有变化:SELECT * FROM t_order WHERE user_id = 42 由中间件改写成对 ds0.t_order_x 的单表查询。
四、常见追问
Q1:分库分表与读写分离、分区有什么区别? 读写分离只分担读流量,写与容量瓶颈照旧;分区(Partition)由数据库自己拆文件,仍在同一实例,突破不了单机上限;分库分表在应用层或中间件层完成,能真正横向扩展。
Q2:拆完一定要引入中间件吗?
不一定。表数量少、路由简单时,在 DAO 层用 user_id % 4 拼表名即可;需要跨库事务、归并分页、在线扩容时,ShardingSphere、Vitess 这类中间件更省心。
Q3:拆得越细越好吗? 不是。每多一个库就多一份连接池、备份、监控和 DDL 成本;上千张表的路由与运维复杂度远超收益。常见做法是「逻辑分片数一次定够,物理节点按需扩」。
小结
- 垂直拆分按业务或字段,水平拆分按行;只有水平拆分才需要分片键与路由算法。
- 分表治容量,分库治并发与连接数,两者可独立也可叠加。
- 上分片前先排除索引、SQL、归档能解决的问题;拆得越细,运维成本越高。