分库分表需满足单表超2000万行、COUNT(*)超2秒、主从延迟超30秒三类信号;优先优化索引与缓存,慎选sharding-jdbc或MyCat,分片键应选业务主键如user_id,避免create_time或UUID,跨分片查询用分片键过滤或ES,ID用TinyID/Snowflake,分布式事务推荐最终一致性。

分库分表到底该不该做?先看这三类信号
不是所有高并发系统都必须分库分表。真正需要动手的,通常是以下情况:单表数据量持续超过2000万行、SELECT COUNT(*) 响应超2秒、主从延迟长期大于30秒且无法通过索引/读写分离缓解。如果只是QPS高但数据量小,优先考虑缓存+连接池优化;如果慢查询集中在某几个字段,先确认EXPLAIN结果是否走了索引——很多“以为要分”的问题,其实是缺失复合索引或LIKE '%xxx'滥用导致的。
水平拆分选 sharding-jdbc 还是 MyCat?关键看团队能力
sharding-jdbc(现为 Apache ShardingSphere-JDBC)是JDBC层代理,无额外中间件运维成本,适合已有Spring Boot项目快速接入;MyCat是独立MySQL代理,支持跨库JOIN和分布式事务语法,但配置复杂、版本迭代慢,线上出问题时排查链路更长。实际选型建议:
- 团队熟悉Java、有自研中间件能力 → 用
sharding-jdbc,可精准控制分片逻辑(比如按user_id % 4分库 +order_time年月分表) - DBA能力强、应用层不愿改SQL → 用
MyCat,但必须禁用SELECT *和非分片键WHERE,否则全表扫描打穿所有库 - 新项目直接上
ShardingSphere-Proxy(轻量版MyCat),兼顾协议兼容与可控性
INSERT 和 UPDATE 的分片键选错,比不拆还危险
分片键一旦选定就极难变更。常见错误是用自增id当分片键——看似均匀,但会导致写入热点(所有新订单集中到同一库表),同时丧失按用户维度查询的能力。正确做法:
- 业务主键优先:如
user_id(查用户订单快)、tenant_id(SaaS多租户隔离) - 组合键兜底:如
concat(user_id, '_', date_format(order_time, 'yyyyMM')),避免单一分片键倾斜 - 绝对避开:
create_time(时间递增=热点)、UUID(字符串散列不均,且索引效率低)
验证方法:上线前用真实流量压测,检查各分片的SHOW TABLE STATUS行数偏差是否在±15%内。
立即学习“Java免费学习笔记(深入)”;
跨分片 ORDER BY LIMIT 和全局唯一ID怎么破?
分库后SELECT * FROM order ORDER BY create_time DESC LIMIT 20会变成“每个库取20条,内存合并再截20条”,结果不准且性能差。解决方案:
- 强制带上分片键:如
WHERE user_id IN (1001,1002),让路由明确到具体库表 - 用ES或Doris做异构索引:把订单关键字段同步过去,查列表走搜索,详情再回库
- 全局ID不用
UUID:推荐TinyID(号段模式)或Snowflake(注意时钟回拨),避免DB生成ID带来的跨库竞争
最容易被忽略的是分布式事务——sharding-jdbc的Seata集成在高并发下容易超时,生产环境建议用最终一致性:本地事务写成功后发MQ,下游消费补偿。










