分库分表的决策时机
单表数据量超过5000万行、单库IOPS到达磁盘上限、慢查询频发且索引优化已到瓶颈——这是考虑分库分表的典型信号。分库分表不是银弹,引入后会增加运维复杂度和查询限制。在决定之前,优先尝试:读写分离、冷热数据归档、缓存前置、SQL优化。只有这些手段全部用尽后,才启动分库分表。
ShardingSphere-JDBC核心配置
ShardingSphere-JDBC以JAR包方式嵌入应用,对业务代码零侵入。通过YAML配置分片规则:
mode:
type: Standalone
repository:
type: JDBC
dataSources:
ds_0:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://10.0.1.10:3306/order_db_0
username: root
password: ${DB_PASSWORD}
ds_1:
dataSourceClassName: com.zaxxer.hikari.HikariDataSource
driverClassName: com.mysql.cj.jdbc.Driver
jdbcUrl: jdbc:mysql://10.0.1.11:3306/order_db_1
username: root
password: ${DB_PASSWORD}
rules:
- !SHARDING
tables:
t_order:
actualDataNodes: ds_${0..1}.t_order_${0..15}
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: order-table-inline
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: order-db-mod
keyGenerateStrategy:
column: order_id
keyGeneratorName: snowflake
t_order_item:
actualDataNodes: ds_${0..1}.t_order_item_${0..15}
tableStrategy:
standard:
shardingColumn: order_id
shardingAlgorithmName: order-table-inline
databaseStrategy:
standard:
shardingColumn: user_id
shardingAlgorithmName: order-db-mod
shardingAlgorithms:
order-table-inline:
type: INLINE
props:
algorithm-expression: t_order_${order_id % 16}
allow-range-query-with-round-robin: true
order-db-mod:
type: MOD
props:
sharding-count: 2
keyGenerators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 1
这个配置实现2库×16表=32个分片。user_id决定数据落在哪个库(取模),order_id决定落在哪个表。分库键和分表键不同,这是常见的用户维度分库+订单维度分表的组合策略。
分片键的选择原则
分片键的选择直接决定了查询效率。核心原则:
1. 分片键必须覆盖80%以上的查询条件。如果多数查询不带分片键,会退化为全分片扫描
2. 分片键的值分布要均匀。自增ID做分片键会导致热点,推荐用雪花ID或hash
3. 关联表的分片键要对齐。订单表和订单明细表用同一个分片键(order_id),保证关联查询在同一分片内完成
4. 避免使用会变更的字段做分片键。分片键一旦确定,数据迁移成本极高
跨分片查询与归并排序
分库分表后,部分查询需要扫描多个分片。ShardingSphere支持跨分片查询并自动归并结果:
// 带分片键的查询:路由到单个分片,性能最优
SELECT * FROM t_order WHERE user_id = 1001 AND order_id = 202607290001
// 不带分片键的查询:全分片扫描,性能差
SELECT * FROM t_order WHERE status = 'PAID' AND create_time > '2026-07-01'
// 分页查询:需要在所有分片上执行后归并
SELECT * FROM t_order WHERE user_id = 1001 ORDER BY create_time DESC LIMIT 10
深分页是分库分表场景的性能杀手。LIMIT 100000, 10在单库时只需跳过10万行,但在32分片场景下,每个分片都要返回前100010行到协调层归并,内存和网络开销暴增。解决方案:
// 方案1:游标分页(推荐)
// 用上一页最后一条记录的值作为下次查询起点
SELECT * FROM t_order
WHERE user_id = 1001 AND create_time < '上一页最后一条的create_time'
ORDER BY create_time DESC LIMIT 10
// 方案2:禁用深分页,强制使用搜索条件缩小范围
// 产品侧限制翻页深度,或提供筛选条件引导用户缩小查询范围
分布式主键生成策略
分库分表后,自增主键不再唯一。ShardingSphere内置多种分布式主键生成器:
// 雪花算法:时间有序,索引友好
keyGenerators:
snowflake:
type: SNOWFLAKE
props:
worker-id: 1 # 每个实例唯一
max-vibration-offset: 1 # 防止时钟回拨
// UUID:无序,索引性能差,不推荐用于MySQL InnoDB
// NanoID:短ID,适合对外暴露的ID
雪花ID在MySQL InnoDB中表现最佳,因为聚簇索引按主键顺序写入,避免页分裂。UUID作为主键会导致随机I/O,写入性能下降约30%。
数据迁移:从单库到分库的无缝切换
将存量数据从单库迁移到分库分表,需要双写方案保证不停机:
迁移步骤:
1. 部署ShardingSphere配置,但流量仍走旧单库
2. 开启双写:应用同时写入旧库和新分片库
3. 运行数据同步脚本,将旧库存量数据迁移到新分片库
4. 对比校验:逐表逐行对比新旧库数据一致性
5. 读流量切到新分片库,写流量继续双写
6. 验证读流量正常后,关闭旧库写入
7. 观察一周无异常后,下线旧库
# 数据同步脚本核心SQL(按分片规则路由写入)
INSERT INTO ds_${user_id % 2}.t_order_${order_id % 16}
SELECT * FROM old_db.t_order
WHERE MOD(user_id, 2) = ${ds_id}
AND MOD(order_id, 16) = ${table_id}
整个迁移过程的关键是步骤4的数据校验。校验不光比行数,还要比关键字段的checksum。建议写校验脚本,每1000行比对一次MD5,发现不一致立即告警并暂停迁移。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/shardingsphere-fen-ku-fen-biao-shi-zhan-pei-zhi-cong-dan-ku/