分库后join查不到数据,因跨库join被架构禁止,sql只发往单一分片;count(*)跨分片不准,需显式启用聚合;分表键缺失导致全库扫描;insert...select跨分片通常失败。

分库后 JOIN 查不到数据,是因为根本没在同一个库执行
跨库 JOIN 在绝大多数分库中间件(如 ShardingSphere、MyCat)里默认不支持,不是配置问题,是架构层面被禁止的。数据库连接只发往一个分片,另一个库的表压根不在当前连接上下文中。
常见错误现象:Table 'db2.user_order' doesn't exist 或查出空结果但单表能查到数据;用 EXPLAIN 会发现只走了其中一个库的执行计划。
- 必须拆成多次查询:先查主表(如
user),拿到分片键值(如user_id),再按路由规则拼出目标库名,查关联表(如order) - 如果关联字段不是分片键(比如用
order_no关联user_id),就得走全局广播查询或冗余字段(如把user_name冗余进order表) - ShardingSphere 的
Broadcast Table只适用于小而慢变的维度表(如dict_type),别硬套在业务主表上
SELECT COUNT(*) 跨分片不准,因为没合并结果
分库后,COUNT(*) 默认只在单个分片执行,返回的是该分片数量。中间件不会自动求和,除非显式启用聚合能力且 SQL 写法合规。
使用场景:后台分页总数、数据量大盘监控——这类地方最容易踩坑,前端显示“共 12 条”,实际有上千条。
- ShardingSphere 需开启
sql-show: true并观察日志,确认是否生成了SELECT COUNT(*) FROM t_order AS t_order_0 UNION ALL SELECT COUNT(*) FROM t_order AS t_order_1这类语句 - 避免写
SELECT COUNT(*) FROM t_order WHERE status = ? GROUP BY user_id—— 分组 + 跨分片 count 几乎必然不支持 - 对精度要求不高的场景,可用
SHOW TABLE STATUS各分片行数估算,但注意 InnoDB 的rows是估算值,误差可能达 50%
分表键选错导致 WHERE 条件无法下推,全库扫描
分表键(sharding key)决定数据路由。如果 WHERE 条件里没有它,中间件无法判断查哪个表,只能把 SQL 发给所有子表,性能断崖式下跌。
典型表现:原本毫秒级查询变成秒级,SHOW PROCESSLIST 看到大量连接卡在 Sending data,慢日志里出现几十个 t_order_001 到 t_order_099 的重复执行。
- 高频查询字段优先设为分表键,比如订单查询多按
user_id,就别用order_time当分表键 - 复合分表键(如
[user_id, order_time])要确保查询条件至少命中前缀,WHERE order_time > '2024-01-01'依然会扫全表 - 想支持多维度查询?加覆盖索引不行,得建影子表(如按
order_no分的另一套表),或引入 Elasticsearch 做异构索引
INSERT ... SELECT 跨分片失败,中间件通常直接拒绝
这类语句天然涉及源表和目标表的跨库/跨表定位,ShardingSphere 从 5.0 开始才有限支持,且要求源表和目标表在同一逻辑库、分片规则兼容。多数生产环境直接报 UnsupportedOperationException。
使用场景:批量导入、报表归档、冷热分离迁移——这些操作一旦卡住,容易引发上游重试风暴。
- 绕过方案:先
SELECT出数据(注意内存溢出风险),在应用层按目标分片规则分组,再逐批INSERT - 如果源表本身也分库,必须先做
UNION ALL汇总,再分发,中间不能有聚合函数(如MAX())、LIMIT或子查询 - 别依赖
REPLACE INTO或INSERT IGNORE的原子性——分片环境下,唯一键冲突检测只在单表生效,跨分片重复插入可能成功两次
分库分表不是加个中间件就完事,每个查询背后都藏着路由决策。最常被忽略的,是那些看起来“应该能跑”的 SQL——它们往往在测试环境安静运行,上线后突然拖垮整个集群。










