分布式环境下Nest Loop Join性能骤降900倍?一文讲透NLJ的跨机Rescan问题与优化方案

一、背景

最近帮群友排查一个案例:某SQL从MySQL迁移到OceanBase后,执行时间从300ms飙到8秒。看执行计划是Nest Loop Join(NLJ),左表输出900行,右表在另一个节点,结果触发了900次远程RPC ——这就是分布式环境下NLJ最经典的“跨机Rescan”陷阱。

二、NLJ的工作原理与优势

在单机TP场景下,NLJ是非常优雅的算法:

  • 条件下推 :能把连接条件t1.id = t2.id 转换成右表的过滤条件t2.id = ? ,让右表走索引快速定位
  • 流式执行 :每迭代出左表一行,立刻去右表匹配,匹配成功即可向上返回。配合LIMIT 子句,扫描量可以极小化

但以上优势的前提是:右表和左表在同一个节点上

三、分布式下的性能灾难

场景还原 :左表输出900行,右表在远程节点,分区键与连接键不匹配。

text

执行流程: 1. 左表扫描出第1行 → 发起RPC去远程节点查右表 → 等待返回 2. 左表扫描出第2行 → 再次发起RPC → 等待返回 … 900行 → 900次RPC

实测数据显示,这种场景下右表算子的耗时比其他算子高2-3个数量级 。如果右表还是分区表且无法裁剪,Rescan次数会进一步放大:假设右表有50个分区,每次Rescan要迭代所有分区,性能直接再降5倍

四、OceanBase的优化手段:Batch Rescan

针对跨机Rescan,OceanBase内核实现了Batch Rescan 机制:

  • 左表先攒批(比如1000行)
  • 一批数据合并成一次RPC,批量去远程节点查询
  • 将900次RPC合并为1次,耗时可降低近900倍

如何确认是否触发了Batch Rescan?
查看执行计划,如果JOIN算子显示use_batch=true ,说明已启用批量优化。

五、优化建议

场景 推荐方案 原理
连接键=分区键 保持现状,可触发分区裁剪 右表Rescan时只扫一个分区
连接键≠分区键,但数据量小 强制走Hash Join(USE_HJ 避免多次RPC
连接键≠分区键,数据量大 考虑调整分区策略,或通过Table Group将关联表leader放在同节点 数据同分布,跨机变本地
无法调整 依赖Batch Rescan 内核级优化,减少RPC次数

六、总结

NLJ本身是好算法,但在分布式环境下必须警惕跨机Rescan 。排查时优先看执行计划中是否有大量remote 算子,以及右表是否被反复扫描。用好Batch Rescan和分区裁剪,能把性能拉回正轨。

【参考文献】

  • OceanBase技术内幕:Nest Loop Join使用姿势分享
  • 分区策略与索引设计优化分布式查询性能

【标签】 #Nest Loop Join #分布式执行 #性能调优 #SQL优化

感谢分享