一、背景
最近帮群友排查一个案例:某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优化