分库分表
分库分表是单库单表容量/性能到达上限后的水平扩展手段:分表拆散单表数据量,分库分散单库连接与磁盘压力。它不是银弹——引入分布式事务、跨库 JOIN、全局 ID 等复杂度,因此判定"该不该拆"比"怎么拆"更重要。典型阈值参考:单表行数超过千万级、单库连接数打满、磁盘 IO 饱和时启动评估。
拆分维度
| 方式 | 拆什么 | 解决 | 代价 |
|---|---|---|---|
| 垂直分表 | 把宽表按列拆成冷热两张表 | 单行数据大、热门字段 IO 竞争 | 跨表查询需 JOIN |
| 垂直分库 | 按业务域拆成独立库(订单库/用户库) | 单库连接数、磁盘压力 | 跨库事务 |
| 水平分表 | 同一张表按分片键拆成多张表(order_0..order_9) | 单表数据量过大 | 全局唯一 ID、跨表聚合 |
| 水平分库 | 分表基础上把分片分布到多台机器 | 单库连接数、IO | 跨库 JOIN、分布式事务 |
垂直拆分是"业务域解耦"(每个库表结构不同),水平拆分是"数据量分摊"(表结构相同、数据分片)——两者可叠加:先垂直分库,再对超大表水平分表。
水平分片键与路由
水平拆分核心是选分片键(shard key)与路由算法,分片键必须满足"访问最频繁的查询能带它":
| 路由算法 | 规则 | 优点 | 缺点 |
|---|---|---|---|
取模 id % N | 按主键取模分片 | 简单均匀 | 扩容需迁移数据(N 变化全部重映射) |
| 范围分片 | 按 id 区间分片(1-1kw 表A) | 扩容友好、范围查询自然 | 数据倾斜(热点区间集中) |
| 一致性哈希 | 环形空间顺时针找节点 | 扩容只迁移相邻区间 | 实现复杂(见 服务治理 的一致性哈希) |
// 取模路由:orderId % 4 → 落到 0/1/2/3 号表
int table = Math.abs(orderId.hashCode()) % 4; // order_0 ~ order_3分片键的约束
不带分片键的查询必须全分片扫描(广播查询),性能差。分片键要选"高频且均匀"的字段:订单按 user_id 分片(用户查自己订单),而非按 order_id。分片后主键不再全局唯一,需分布式 ID(见 分布式系统 的分布式 ID:雪花算法/号段)。
中间件方案
| 方案 | 定位 | 特点 |
|---|---|---|
| ShardingSphere-JDBC | 应用内 JDBC 层分片(推荐) | 轻量、无额外组件、代码侵入低,支持分片/读写分离/分布式事务 |
| ShardingSphere-Proxy | 独立代理层 | 对应用透明,多语言友好,多一跳网络 |
| MyCat | 独立代理(早期方案) | 历史项目存量,新项目少用 |
# ShardingSphere-JDBC 配置(application.yml)
spring:
shardingsphere:
datasource:
names: ds0, ds1
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds${0..1}.t_order_${0..3}
table-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: mod拆分的代价与边界
| 代价 | 说明 | 缓解 |
|---|---|---|
| 分布式事务 | 跨分片写不再有单库事务 | Seata AT/TCC(见 seata)、本地消息表 |
| 跨分片 JOIN | 分片间不能 JOIN | 冗余字段、应用层聚合、宽表 |
| 全局唯一 ID | 自增主键冲突 | 雪花算法、号段模式 |
| 排序/分页 | ORDER BY LIMIT 需各分片取再合并 | 按分片键规划查询、避免深分页 |
| 扩容迁移 | 取模方案扩容需重映射 | 一致性哈希、双写过渡、range 分片 |
不要过早拆分
单表千万级以内、连接数未饱和时,先做优化(索引、读写分离、缓存)而不是分库分表——分库分表是"最后手段",复杂度(事务、JOIN、ID、运维)远高于收益。经典演进路径:单库 → 读写分离 → 缓存 → 垂直拆分 → 水平拆分,每步确认瓶颈真的在"这一步"。
常见问题
| 问题 | 处理 |
|---|---|
| 分片后如何做唯一约束 | 唯一索引需带分片键,或接受"分片内唯一" |
| 历史大表拆分 | 影子表双写过渡:新写双份,校验一致后切换 |
| 扩容迁移 | 停机窗口小→一致性哈希;可停→取模直接重分布 |
分库分表与 数据库范式 的规范化(拆分前先规范化)、MySQL 的主从复制(分片后每片仍做主从)、seata 的分布式事务(跨分片写)共同构成数据库扩展体系。