SQL 分表分库策略与应用方法

1次阅读

分库后join查不到数据是因为sql路由失效,中间件不支持跨库join,需改用应用层组装或确保同分片键路由。

SQL 分表分库策略与应用方法

分库后 JOIN 查不到数据,是因为 SQL 路由失效

分库之后,跨库 JOIN 天然不支持——中间件(如 ShardingSphere、MyCat)或自研路由层通常只按分片键路由单表查询,遇到多表 JOIN 且涉及不同库时,要么报错,要么只查一个库、结果为空或错乱。

常见错误现象:ShardingSphere-JDBCUnsupportedOperationException: Cannot support multiple tables with different data sources in JOINMyCat 返回空结果但无报错;应用层查出的数据明显缺失关联字段。

  • 优先改写业务逻辑:用「两次查询 + 应用层组装」替代 JOIN,比如先查订单列表(带 user_id),再批量查用户信息
  • 若必须 JOIN,确保所有参与表都按同一分片键(如 user_id)分库,且路由规则一致,否则中间件无法对齐数据源
  • 避免在分库场景下使用全局表(如 dict_type)与分片表做 JOIN,部分中间件不自动广播查询,需显式配置 broadcast-tables

sharding-jdbcstandardcomplex 分片策略区别在哪

standard 只支持单分片键(如 order_id),对应一个 sharding-column 和一个分片算法complex 支持多列组合(如 user_id + create_time),但要求所有查询必须包含全部分片列,否则路由失败或全库扫描。

使用场景:standard 适合用户中心类系统(按 user_id 分);complex 常用于订单归档(按 user_id 分库 + create_time 分表),但代价是 WHERE create_time > ? 单独出现时,会遍历所有库。

  • standard 策略下,select * FROM order WHERE user_id = 123 路由精准;但 WHERE order_id = 456 会全库扫
  • complex 策略下,WHERE user_id = 123 AND create_time BETWEEN '2023-01' AND '2023-06' 才能准确定位,缺一不可
  • 性能影响:复杂策略提升写入局部性,但大幅增加查询条件约束,线上误写 WHERE 条件极易引发慢查询

分表后 MAX(id)ORDER BY id DESC LIMIT 1 拿不到最新记录

分表后 id 不全局唯一,各表独立自增,MAX(id) 返回的是当前表最大值,不是整个逻辑表最新写入记录;ORDER BY id DESC LIMIT 1 同理,只查单表,可能漏掉其他分表里更晚插入的高 id 记录。

典型错误:用 id 当时间序标识做同步、轮询或翻页,导致漏数据或重复处理。

  • 正确做法是引入逻辑时间字段,如 create_time(精度到毫秒),并确保写入时严格单调;查询用 ORDER BY create_time DESC LIMIT 1
  • 如果必须依赖递增编号,改用分布式 ID 生成器(如 snowflakeleaf),确保全局有序,再按该字段分片
  • 避免在分表场景下用 SELECT LAST_INSERT_ID() 获取刚插入记录的完整状态——它只返回当前物理表的 ID,不反映路由后的实际归属

跨分片 count(*)GROUP BY 性能差,根本原因不是 SQL 写法

这类聚合操作慢,不是因为没加索引或没写对 SQL,而是中间件必须把请求下发到所有分片,拉回全部原始数据,在内存中合并计算。数据量大时,网络传输和应用层 CPU 成瓶颈,比单库慢数倍甚至十倍。

兼容性影响明显:ShardingSphere 5.x 默认开启 merge 引擎,但超过 10 个分片 + 百万级行时,jvm 常因 OOM 中断;MyCat 则可能直接超时断连。

  • 能预计算就预计算:比如用定时任务更新 daily_order_count 表,而不是每次查 SELECT COUNT(*) FROM order WHERE create_time > ?
  • 接受近似结果:用 HyperLogLog 或采样(如 LIMIT 10000 后统计)替代精确聚合,尤其用于监控看板
  • 强制下推失败时,检查是否用了不支持下推的函数,如 DATE_FORMAT(create_time, '%Y-%m') 会导致整个 GROUP BY 无法下推,改用 create_time >= ? AND create_time 区间过滤

分库分表不是银弹,真正难的从来不是怎么切,而是切完之后,那些你以为“还是原来那样查”的地方,全都悄悄变了规则。

text=ZqhQzanResources