1. 为什么需要分库分表?
当单表数据量突破千万级时,MySQL的性能瓶颈会越来越明显。我经历过一个电商项目,订单表达到3000万数据量时,即使有索引,查询响应时间也经常超过2秒。这时就需要考虑分库分表方案。
Sharding-JDBC是Apache ShardingSphere的前身,定位为轻量级Java框架。它通过改写SQL语句,将操作路由到不同的数据库或表,但对应用层完全透明。相比MyCat这类中间件,它采用无中心化架构,性能损耗更小。
重要提示:分库分表不是银弹,它会带来分布式事务、跨库JOIN等新问题。建议单表数据量未达500万时不要过早优化。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与快速入门
2.1 基础环境搭建
需要准备:
- JDK 1.8+
- MySQL 5.7+(建议配置主从复制)
- Maven项目
pom.xml关键依赖:
xml复制<dependency>
<groupId>org.apache.shardingsphere</groupId>
<artifactId>sharding-jdbc-core</artifactId>
<version>4.1.1</version>
</dependency>
2.2 最简单的分表示例
假设我们要对t_order表按order_id分2张表:
java复制// 分片规则配置
ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
shardingRuleConfig.getTableRuleConfigs().add(
new TableRuleConfiguration("t_order", "ds.t_order_${0..1}"));
// 分片算法
shardingRuleConfig.setDefaultDatabaseShardingStrategyConfig(
new InlineShardingStrategyConfiguration("order_id", "t_order_${order_id % 2}"));
3. 核心分片策略详解
3.1 分片算法类型
-
精确分片(=, IN)
java复制PreciseShardingAlgorithm<String> { @Override public String doSharding(Collection<String> availableTargetNames, PreciseShardingValue<String> shardingValue) { // 根据分片值计算目标表 } } -
范围分片(BETWEEN)
java复制RangeShardingAlgorithm<Long> { @Override public Collection<String> doSharding(Collection<String> availableTargetNames, RangeShardingValue<Long> shardingValue) { // 处理范围查询 } }
3.2 分片键选择原则
- 高离散度(如用户ID)
- 避免热点数据(不要用性别作为分片键)
- 业务相关性(经常需要JOIN的字段)
4. 完整分库分表示例
4.1 场景描述
电商系统需要:
- 按user_id分库(2个库)
- 按order_id分表(每个库4张表)
4.2 配置实现
yaml复制spring:
shardingsphere:
datasource:
names: ds0,ds1
ds0: # 主库配置
ds1: # 从库配置
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..3}
database-strategy:
inline:
algorithm-expression: ds$->{user_id % 2}
table-strategy:
standard:
precise-algorithm-class-name: com.example.OrderPreciseShardingAlgorithm
5. 生产环境注意事项
5.1 分布式ID生成
避免使用自增ID,推荐:
- 雪花算法(Snowflake)
- UUID(性能较差)
- 数据库序列(需要中心化)
5.2 常见问题排查
- 全表扫描:没有带上分片键的查询会导致广播路由
- 跨库事务:考虑使用Seata等分布式事务方案
- JOIN性能:尽量在应用层做数据聚合
6. 性能优化实践
6.1 读写分离配置
yaml复制spring:
shardingsphere:
masterslave:
name: ms_ds
master-data-source-name: ds_master
slave-data-source-names: ds_slave0,ds_slave1
load-balance-algorithm-type: round_robin
6.2 结果归并优化
- 流式归并:大数据量时减少内存消耗
- 内存归并:小数据量时响应更快
我在实际项目中发现,对于分页查询一定要使用LIMIT改写:
sql复制-- 错误写法(性能差)
SELECT * FROM t_order WHERE user_id=1 LIMIT 10 OFFSET 20
-- 正确写法
SELECT * FROM t_order_0 WHERE user_id=1 LIMIT 30
UNION ALL
SELECT * FROM t_order_1 WHERE user_id=1 LIMIT 30
-- 应用层再做结果合并和分页
7. 监控与运维
建议集成Prometheus监控:
java复制ShardingSphereDataSource dataSource = ...;
Collection<ShardingSphereMetric> metrics = dataSource.getRuntimeContext().getMetric();
for (ShardingSphereMetric metric : metrics) {
metric.register(); // 注册到监控系统
}
关键监控指标:
- SQL执行耗时
- 连接池状态
- 路由结果统计
踩坑经验:线上环境一定要配置慢SQL日志,我们曾发现一个没有分片键的查询导致全库扫描,直接拖垮了整个集群。
