SQL 为什么要做分库分表?

分库分表是高并发写入超限后的硬需求,需权衡时机、分片键选择、全局ID生成、中间件选型及聚合查询优化,核心在于业务能否接受最终一致性与分布式妥协。

单库单表撑不住高并发写入时,分库分表是硬需求

INSERTUPDATE 请求持续超过每秒几千次,且主库 CPU 常年 >80%、慢查询陡增、主从延迟飙升到分钟级,说明单实例的写能力已触顶。MySQL 单表超过 5000 万行后,即使有索引,ALTER TABLE 可能锁表数小时,DELETE 旧数据也容易拖垮复制线程。这不是“要不要做”,而是“再不做线上就要抖动甚至挂掉”。

分库分表不是越早越好,但拖到主键自增溢出就晚了

过早分库分表会引入路由复杂度、跨库事务难保证、JOINGROUP BY 变得低效甚至不可用。常见误判点:只看数据量,不看访问模式。比如日志类表虽有百亿行,但基本只按时间范围 SELECT,用分区表(PARTITION BY RANGE)就够了;而用户订单表既有高频按 user_id 查询,又有按 order_no 查单条,这才真正需要分库分表。

  • 分库前必须确认业务能否接受最终一致性——分布式事务(如 Seata)代价远高于应用层补偿
  • 分表键选错会导致热点,比如用 create_time 分片,所有新订单都打到最新分片,其他分片闲置
  • 自增主键在分库后失效,必须改用 SNOWFLAKEUUID 或号段模式生*局唯一 id

ShardingSphere 和 MyCat 的核心差异在 SQL 兼容性上

如果你的业务重度依赖 SELECT * FROM t1 JOIN t2 ON t1.id = t2.t1_id,优先选 ShardingSphere-JDBC:它在 JDBC 层解析 SQL,支持部分跨库 JOIN 和子查询;而 MyCat 是代理层,对复杂嵌套查询支持弱,且一旦配置错误,可能直接返回空结果而非报错。

  • ShardingSphere 要求明确声明分片规则,比如 t_orderuser_id % 4 分 4 库,t_order_item 必须用相同算法,否则关联查不出数据
  • MyCatscheme.xml 里写错一个 dataNode 名称,连接不报错但所有写入静默失败——务必用 show databases;show tables; 验证路由是否生效
  • 两者都不支持 SELECT ... FOR UPDATE 跨库加锁,涉及资金扣减等强一致性场景,得退回到单库或改用 TCC 模式

分库后 COUNT(*)、ORDER BY LIMIT 100 这类聚合操作最易翻车

分库分表后,COUNT(*) 不再是 O(1),而是要扫所有分片再合并;ORDER BY create_time DESC LIMIT 100 会被改写成每个分片取 100 条,再内存排序取前 100——实际扫描行数可能是原来的 N 倍(N=分片数)。这类查询响应时间会随分片数线性恶化。

  • 统计类需求尽量走离线数仓(如 Doris / StarRocks),别压在交易库上
  • 分页深度超过 1000 时,强制要求前端传 last_create_time 做游标分页,避

    LIMIT 10000, 20
  • 如果必须实时 COUNT,可在写入时用 Redis HyperLogLog 做近似去重,误差率可控在 0.81%

分库分表真正的门槛不在技术实现,而在业务逻辑是否愿意为分布式妥协——比如放弃跨用户汇总报表,或接受“最近 7 天订单数”有 2 秒延迟。这些决策比选哪个中间件重要得多。