水平分表核心思路与方法
什么是水平分表
水平分表(Horizontal Partitioning 或 Sharding)是将同一张表的数据行分散到多个结构完全相同的子表中。每张子表都拥有相同的字段,但只存储一部分数据行。
原表 order:1 亿行
拆分为:
order_0(user_id % 10 = 0):1000 万行
order_1(user_id % 10 = 1):1000 万行
...
order_9(user_id % 10 = 9):1000 万行
核心设计思路
1. 选择分片键
分片键(Shard Key)是决定数据分配到哪张子表的关键字段。选对分片键是水平分表成败的核心。
好的分片键特征:
– 查询频率高:大多数查询都能带上这个字段
– 分布均匀:数据在各个分片上大致相等
– 不可变性:不会修改,或修改成本低
常见的分片键:
– user_id:适合以用户维度的业务
– order_id:适合以订单维度的业务
– tenant_id:适合 SaaS 多租户场景
2. 确定分片数量
分片数量由当前数据量和未来增长预期决定:
分片数 = (预估最大数据量) / (单表理想行数)
单表理想行数通常控制在 500 万到 2000 万之间。分片数应是 2 的幂(2、4、8、16…),便于后续扩容。
3. 分片路由算法
取模分片
int shardId = orderId % shardCount;
String tableName = "order_" + shardId;
范围分片
// 假设每个分片 1000 万行
int shardId = orderId / 10_000_000;
一致性哈希分片
参考后续第 120 篇的详细说明。
水平分表的两种形式
单库内分表
所有子表在同一个数据库中,但数据行分散:
数据库 order_db
├── order_0(user_id mod 10 = 0-2)
├── order_1(user_id mod 10 = 3-5)
├── order_2(user_id mod 10 = 6-8)
└── order_3(user_id mod 10 = 9)
优点:跨表查询可以使用 UNION ALL 在数据库层完成
缺点:仍然受单机 CPU/IO/内存资源限制
分库 + 分表
子表分布到不同的数据库实例:
order_db_0 order_db_1
order_0, order_1 order_4, order_5
order_2, order_3 order_6, order_7
优点:突破单机资源上限,线性扩展
缺点:跨库操作更复杂
实施步骤
第 1 步:数据拆分策略设计
确定分片键、分片数、路由算法,并设计数据迁移方案。
第 2 步:建立分片表
-- 如果使用 Sharding-JDBC,只需要定义逻辑表
-- 物理表自动创建
CREATE TABLE order_0 (id BIGINT, user_id BIGINT, ...);
CREATE TABLE order_1 (id BIGINT, user_id BIGINT, ...);
-- ...
第 3 步:修改数据访问层
使用中间件(如 Sharding-JDBC)或手动在 DAO 层实现路由逻辑:
// 使用 Sharding-JDBC 时,配置分片规则即可
// select * from order where user_id = ? → 自动路由到正确的表
@ShardingRule(databaseStrategy = "user_id % 2", tableStrategy = "user_id % 4")
public interface OrderMapper {
List<Order> getByUserId(@Param("userId") Long userId);
}
第 4 步:数据迁移与验证
- 停止写入,将旧表数据按规则分发到各分片
- 或使用双写方案在线迁移
水平分表后不能做什么
| 操作 | 解决方案 |
|---|---|
| 跨分片 JOIN | 应用层聚合或宽表冗余 |
| 全局排序 ORDER BY | 各分片分别排序后归并 |
| 全局 COUNT | 使用辅助计数表或缓存 |
| 自增主键 | 换用雪花算法或其他分布式 ID |
| 跨分片唯一约束 | 需要全局去重中间件 |
面试要点
- 水平分表的核心是:选对分片键 + 好路由算法 + 可扩展的分片数
- 取模分片最简单但扩容困难,范围分片方便扩容但可能数据倾斜
- 水平分表后 SQL 能力受限,需要在应用层弥补
- 不是所有表都需要水平分表,只对数据量最大的那部分表做水平拆分
- 实施前必须设计好数据迁移和灰度方案
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容