在设计 3000万数据的分库分表方案 时,需综合考虑 数据增长趋势、查询模式、硬件资源、业务容忍度 等因素。以下是分库分表的具体方案及核心逻辑分析:
一、分库分表的核心原则
原则 说明
单表容量控制 单表建议不超过1000万行(B+树深度3~4层,查询效率较高)
分片键均匀性 避免数据倾斜(如用户ID哈希分片优于按时间范围分片)
扩展性预留 设计时预留2~3倍容量,避免频繁扩容
跨分片查询最小化 减少跨库/跨表JOIN,优先通过分片键定位数据
二、3000万数据的分库分表示例
方案1:2库 × 16表 = 32分片
分片逻辑:
分片键:用户ID(哈希取模 user_id % 32)。
每个分片数据量:3000万 / 32 ≈ 94万/分片。
预留容量:单分片可支持至200万(总容量6400万)。
配置示例:
yaml
复制
分片规则(ShardingSphere配置示例)
sharding:
tables:
user:
actualDataNodes: db${0..1}.user_${0..15}
tableStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: user_hash_mod
shardingAlgorithms:
user_hash_mod:
type: HASH_MOD
props:
sharding-count: 32
方案2:4库 × 8表 = 32分片
分片逻辑:
分库键:user_id % 4(4个物理库)。
分表键:user_id % 8(每个库8张逻辑表)。
单库负载:3000万 / 4库 = 750万/库,单表94万。
优点:
更细粒度的负载均衡(多库分散连接数压力)。
便于按库做物理隔离(如不同库部署到不同服务器)。
三、分库分表数量计算公式
根据业务需求动态调整分片数:
分片总数
预估最大数据量
单分片推荐容量
×
冗余系数(
1.5
2.0
)
分片总数=
单分片推荐容量
预估最大数据量
×冗余系数(1.5 2.0)
示例:
预估最大数据量:1亿
单分片容量:500万
分片总数:1亿 / 500万 × 1.5 = 30分片 → 最终取32(最接近的2的幂次,方便哈希计算)。
四、分片键选择建议
分片键类型 适用场景 示例
业务主键 强一致性需求(如订单ID) order_id % 分片数
时间范围 时序数据(如日志、监控数据) 按月分表:log_202301
地理哈希 地域分布业务(如用户归属地) region_code % 分片数
五、Java代码实现分片路由
以用户ID哈希分片为例,实现简单路由逻辑:
java
复制
public class ShardingRouter {
// 分片总数(库数 × 表数)
private static final int SHARD_TOTAL = 32;
/**
* 计算用户数据所在的分片位置
* @param userId 用户ID
* @return 格式:db{库编号}_table{表编号}
*/
public static String routeShard(String userId) {
int hash = Math.abs(userId.hashCode());
int shardNo = hash % SHARD_TOTAL;
// 假设分片规则为4库 × 8表
int dbNo = shardNo / 8; // 计算库编号(0~3)
int tableNo = shardNo % 8; // 计算表编号(0~7)
return String.format("db%d_table%d", dbNo, tableNo);
}
public static void main(String[] args) {
String userId = "user_12345";
String shard = routeShard(userId);
System.out.println("数据路由到: " + shard); // 输出示例: db2_table5
}
}
六、注意事项
热点问题:
若分片键为自增ID,可能导致新数据集中在末尾分片,改用哈希分片或组合分片键(如 用户ID + 时间)。
扩容方案:
一致性哈希:减少数据迁移量。
双倍扩容:分片数翻倍,迁移50%数据(如32分片→64分片)。
工具支持:
使用 ShardingSphere、MyCat 等中间件自动化分片路由。
避免手动实现复杂分片逻辑。
总结
推荐方案:3000万数据建议分为 4库 × 8表 = 32分片,单分片约94万数据,预留扩展性。
分片键选择:优先使用业务主键哈希,确保数据均匀分布。
中间件:使用ShardingSphere简化分库分表管理,减少代码侵入。