Prompts-MCP 686 skills · ai / design / design-pattern / framework / fundamentals / habit / lang / tech-selection /mcp/sse
framework framework/sharding-sphere/distributed-limitations.md high

sharding-sphere-distributed-limitations

ShardingSphere 分布式限制 — 跨库 JOIN 不支持、跨片分页深翻页内存放大、聚合需中间件归并、跨片事务退化为分布式事务,各有规避手段。Use when 跨片查询报错或结果不对 / 深分页 OOM / 评审分片下 JOIN 聚合事务时。

分布式限制跨库 join跨片分页跨片聚合分布式事务深分页
paths
  • *.java
  • *.yml

ShardingSphere · 分布式限制

本条只管「分片后哪些操作受限及怎么绕」。绑定/广播表避 join 见 broadcast-binding-table.md;读写一致见 read-write-split.md

四类限制与规避

操作 限制 规避
跨库 JOIN 不同分片键的表无法跨库 join 广播表/绑定表落同片;冗余宽表;应用层分别查再内存组装
跨片分页 LIMIT m, n 要从每片各取前 m+n 行再归并,深翻页内存暴涨 改键集分页(上次最大 id / 游标),避免大 offset
跨片聚合 SUM/COUNT/AVG/GROUP BY/ORDER BY 要查所有片再归并 中间件能归并但慢;高频聚合走预聚合表或 ES/数仓
跨片事务 一笔事务跨多片即退化为分布式事务,性能与一致性代价大 让一笔业务落单片;必须跨片用 XA 或 Seata(见 seata 模块)

深分页为何爆内存

跨片 LIMIT 100000, 10:中间件无法只取某片第 10w 行,必须让每个分片都返回前 100010 行再全局排序取第 10w~10w+10 行。分片越多、offset 越大,拉回内存的行数成倍放大 → 慢且 OOM。

正例

-- ✅ 键集分页替代深 offset:带分片键 + 上次最大 id,命中单片不归并
SELECT * FROM t_order
WHERE user_id = 1001 AND id > #{lastMaxId}
ORDER BY id LIMIT 10;
// ✅ 不同分片键的两表跨库:分别查再内存组装,不写跨库 JOIN
final List<OrderDO> orders = orderMapper.listByUser(userId);
final List<Long> pids = orders.stream().map(OrderDO::getProductId).toList();
final Map<Long, ProductDO> products = productMapper.listByIds(pids)   // 走商品分片
        .stream().collect(toMap(ProductDO::getId, p -> p));
orders.forEach(o -> o.setProduct(products.get(o.getProductId())));

反例

-- ❌ 跨片深分页:每个分片各回 1,000,010 行到内存归并 → 慢 + OOM
SELECT * FROM t_order ORDER BY create_time LIMIT 1000000, 10;

-- ❌ 不同分片键的两表直接跨库 JOIN —— 中间件无法路由
SELECT * FROM t_order o JOIN t_product p ON o.product_id = p.id;

理由:分片后单库视角的 JOIN/分页/聚合都变成「全片查 + 归并」,深 offset 把每片的扫描量按 offset 放大;跨片事务退化成分布式事务。能落单片就别跨片,必须跨片的聚合/事务交预聚合表与 Seata。

自检

  • [ ] 跨片深分页改成了键集分页,没用大 offset 的 LIMIT m,n
  • [ ] 不同分片键的表没写跨库 JOIN,改广播/绑定表或应用层组装?
  • [ ] 高频聚合走预聚合表 / ES,没靠中间件实时归并全片?
  • [ ] 业务尽量落单片;确需跨片事务才上 Seata / XA?

相关