单表超亿级需回归百万级可控规模,优先按查询条件选range或hash分片,再通过分库分表+应用层归并、宽表冗余、预聚合表等手段解决跨库join与聚合问题。

单表超亿级后 SELECT 越来越慢,不是索引能扛住的
索引在千万级还管用,到亿级就明显乏力——B+树深度变大、缓冲池命中率暴跌、全表扫描成本高得离谱。这时候加索引、调 sort_buffer_size 或换 SSD,效果都有限。真正要动的是数据组织方式:让单库单表的数据量回到百万级可控范围。
分表选 RANGE 还是 HASH?看查询条件是否带分片键
如果 90% 查询都带 user_id(比如查用户订单),HASH(user_id) 分表最稳,路由明确、无跨表;但要是经常按时间范围查(如“查 2024 年所有订单”),RANGE 按 create_time 分更合适,能利用分区裁剪。
-
HASH分法:容易导致热点(比如某大 V 的订单集中在一个分表) -
RANGE分法:容易产生数据倾斜(比如活动期间写入暴增,某个月分表远大于其他) - 混合用法常见:先
HASH(user_id)分库,再按create_time分表,兼顾路由与范围查询
分库后 JOIN 和 GROUP BY 直接失效,得改写逻辑
跨库无法走 MySQL 原生 JOIN,连 UNION ALL 都得手动拼。常见替代方案不是“模拟”,而是“下沉”:
- 把聚合计算下推到各分表执行,应用层做归并(比如各分表算出各自的
COUNT(*),再相加) - 用宽表思路:把高频关联字段冗余进主表(如订单表里存
user_name),避免反查 - 异步构建汇总表:用
binlog解析 + Flink/Spark 实时写入order_daily_summary这类预聚合表
mycat 或 sharding-jdbc 不是银弹,配置错一个参数就拖垮性能
中间件本身会引入额外延迟和单点风险。最容易踩的坑是分片键选择不当或绑定不牢:
-
sharding-jdbc中若没在 SQL 里显式带上分片键(如WHERE user_id = ?),默认走全路由,100 张表全查一遍 -
mycat的schema.xml里dataNode配错路径,会导致写入直接失败但错误日志只报ERROR 1105 (HY000): unknown error - 连接池必须配在中间件层,不能让应用直连各物理库,否则事务和连接数完全失控
分库分表不是加个中间件就完事,核心在于业务 SQL 必须适配分片逻辑——哪条语句会跨节点、哪个字段必须强制出现在 WHERE 条件里、哪些聚合必须拆成两阶段,这些细节漏掉一个,线上就可能查出慢日志飙升。











