MySQL分库分表教程:从单表瓶颈到水平拆分
单表数据量涨到千万级后,查询开始变慢、加索引也压不住写入时,就该考虑分库分表了。
但分库分表不是越早越好,它解决的是单库单表的容量和并发瓶颈,代价是跨库事务、跨片查询和运维复杂度上升。
这篇教程按“先判断要不要拆、再选分片键、最后用ShardingSphere落地”的顺序讲,跟着做可以完成一次水平分表验证。
什么情况下才需要拆表
先给一个可参考的判断思路,而不是死数字。
单表行数超过约500万到1000万、单表数据文件超过几GB、写入QPS持续偏高、慢查询集中在同一张大表时,才值得评估拆分。
如果只是偶尔慢,优先做索引优化、读写分离或归档历史数据。
分库分表主要分两种:
- 垂直拆分:按业务把不同表拆到不同库,比如订单库、用户库分开。
- 水平拆分:同一张表按规则拆成多张,比如
order_0、order_1,这是本教程重点。
水平拆分的目标是让每条数据有明确归属,查询时能直接定位到某张表,而不是全表扫描。
分片键怎么选
分片键决定数据落到哪张表,选错会导致数据倾斜或跨片查询。
- 优先选查询条件里最常出现的字段,比如订单表用
user_id或order_id。 - 尽量让分片键分布均匀,避免用性别、状态这类基数低的字段。
- 如果要按时间范围查,可考虑时间分片,但要注意热点集中在最新分片。
一个常见做法是订单表按 user_id 取模分片,这样同一用户的订单落在同一张表,按用户查询效率高。
代价是按订单号查时需要额外映射,或让订单号里带分片信息。
用ShardingSphere-JDBC做水平分表
下面以 Spring Boot 项目为例,环境为 MySQL 8.x、ShardingSphere-JDBC 5.x,实际版本请以你项目中依赖为准。
第一步,建两张分表,结构完全一致:
CREATE TABLE t_order_0 (
order_id BIGINT NOT NULL,
user_id BIGINT NOT NULL,
amount DECIMAL(10,2),
PRIMARY KEY (order_id)
);
CREATE TABLE t_order_1 LIKE t_order_0;
第二步,在 pom.xml 引入依赖:
org.apache.shardingsphere
shardingsphere-jdbc-core-spring-boot-starter
5.4.1
第三步,在 application.yml 配置分片规则:
spring:
shardingsphere:
datasource:
names: ds0
ds0:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/demo
username: root
password: your_password
rules:
sharding:
tables:
t_order:
actual-data-nodes: ds0.t_order_$->{0..1}
table-strategy:
standard:
sharding-column: user_id
sharding-algorithm-name: order-inline
sharding-algorithms:
order-inline:
type: INLINE
props:
algorithm-expression: t_order_$->{user_id % 2}
props:
sql-show: true
配置说明:actual-data-nodes 声明真实表,algorithm-expression 用 user_id % 2 决定落表。sql-show: 会打印路由后的 SQL,
true
方便验证。
第四步,启动应用后插入一条 user_id=3 的数据,观察日志中实际执行的 SQL 是否指向 t_order_1。
再去数据库分别查两张表,确认数据只落在其中一张,说明分片生效。
常见报错与避坑
- 报错“actual-data-nodes not found”:检查库名、表名和表达式是否与实际表一致。
- 查询走全路由:SQL 中没有带分片键,ShardingSphere 无法定位单表,会并发查所有分片。
- 跨片分页性能差:
LIMIT分页在分片场景下会归并结果,深分页要改用游标或业务侧限制。 - 分布式主键冲突:分片后不能依赖单库自增,改用雪花算法或号段模式生成主键。
- 跨库事务:尽量让同一事务的数据落在同一分片,否则需要引入 Seata 等方案,复杂度明显上升。
重要提醒:分库分表前先备份数据,在测试环境验证路由规则,再考虑上生产。
效果验证与后续扩容
验证分片是否成功,可以看三点:日志里的路由 SQL、两张分表的数据分布、按分片键查询的响应时间。
如果数据明显倾斜,说明分片键或算法需要调整。
后续扩容时,简单的取模算法在增加分片数后会导致大量数据迁移。
生产环境更常用一致性哈希或预分片方案,把扩容成本提前设计进去。
分库分表是架构层面的改动,建议先在小表上跑通流程,再逐步迁移核心表。
如果你还在单表阶段,先把索引和慢查询优化做好,往往能推迟拆分时间。