如何基于Oracle执行计划判断哈希对比查询的最优方案
咱们来一步步拆解你的三个查询和执行计划,搞清楚哪个效率最高——核心关键点其实在远程表migrated_document@V2_PROD的访问方式上,毕竟跨库操作的网络开销才是影响速度的大头!
先看三个执行计划的核心差异
查询1:左外连接+IS NULL
------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | Inst |IN-OUT| ------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 105K| 51M | 194 | | | | 1 | HASH JOIN RIGHT OUTER| | 105K| 51M | 194 | | | | 2 | REMOTE | MIGRATED_DOCUMENT | 1 | 275 | 2 | V2_MN~ | R->S | | 3 | TABLE ACCESS FULL | DOCUMENT | 105K| 23M | 192 | | | -------------------------------------------------------------------------------------------
这个计划的逻辑是一次性把远程表的所有数据拉到本地(Rows显示1是统计信息的小误差,HASH JOIN RIGHT OUTER的本质是先获取全量远程数据),然后和本地的DOCUMENT表做哈希连接。这正是你猜想它最快的原因:远程访问只做一次,避免了多次网络往返的开销——跨库查询里,单次大传输通常比多次小传输快得多。
查询2:NOT EXISTS
---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | Inst |IN-OUT| ---------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 105K| 23M | 104K | | | | 1 | FILTER | | | | | | | | 2 | TABLE ACCESS FULL | DOCUMENT | 105K| 23M | 192 | | | | 3 | REMOTE | MIGRATED_DOCUMENT | 1 | 50 | 1 | V2_MN~ | R->S | ----------------------------------------------------------------------------------------
这个计划就坑了:它会遍历本地DOCUMENT表的每一行,都远程查询一次migrated_document(FILTER操作会逐行触发REMOTE调用)。你看Cost高达104K,就是因为要执行105K次远程调用——哪怕每次远程查只花10ms,累积起来也要17分钟,实际执行肯定是三个里最慢的,直接排除。
查询3:NOT IN
---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost | Inst |IN-OUT| ---------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 105K| 29M | 526 | | | | 1 | NESTED LOOPS ANTI | | 105K| 29M | 526 | | | | 2 | TABLE ACCESS FULL | DOCUMENT | 105K| 23M | 192 | | | | 3 | REMOTE | MIGRATED_DOCUMENT | 1 | 50 | 0 | V2_MN~ | R->S | ----------------------------------------------------------------------------------------
NESTED LOOPS ANTI比NOT EXISTS稍好一点,Oracle会尝试批量发送本地的哈希值到远程,减少远程调用的次数,但本质还是多次远程访问,只是比逐行调用的开销小一些。不过Cost 526还是远高于查询1的194,速度肯定比不上查询1。
关于“成本更低但速度更慢”的疑问
你担心的这种情况确实存在,但在你的场景里正好相反:
- 查询1的Cost最低(194),而且它的远程访问只做一次,实际执行速度绝对是最快的——跨库查询的最大开销就是网络往返,一次拉取远胜多次调用。
- 你觉得方案1更快的猜想完全正确!
额外优化小建议
如果远程表migrated_document的document_hash字段没有索引,建议在远程库给它建个索引,这样查询1拉取远程数据时会更快;另外,也可以考虑先把远程表的哈希值同步到本地临时表(比如用CREATE GLOBAL TEMPORARY TABLE temp_hash AS SELECT document_hash FROM migrated_document@V2_PROD),再和本地表对比,进一步降低远程IO的影响。
内容的提问来源于stack exchange,提问作者Μenelaοs

