首批通过分布式安全可靠测评,为关键业务系统打造
Merge Join
更新时间:2026-04-07 20:57:20
什么是 Merge Join
Merge Join 其实是 Nested Loops Joins 的一种变种。如果联接的两个数据集尚未排序,则数据库会对它们进行排序。对于第一个数据集中的每一行,数据库会探测第二个数据集中的匹配行并将它们联接起来,其起始位置基于上一次迭代中的匹配。这一点与 Nested Loops Joins 不同,Nested Loops Joins 遍历第二个数据集时每次都是从第一行数据开始。Merge Join 的执行伪代码如下所示。
for row_1 IN (select * from T1 where xxx)
loop
for row_2 IN (select * from T2 where row_num > last_row_num and xxx)
loop
if match join condition(row_1, row_2)
then
output (row_1, row_2)
else
last_row_num = row_num
break
end if
end loop
end loop
优化器什么时候选择 Merge Join
Merge Join 同样适合大数据量的联接,如果联接两侧的数据源都是无序的,或者联接条件是非等值联接,优化器不会选择 Merge Join 算法,而是选择其他联接算法。否则优化器会尝试生成 Merge Join 计划,并通过计划成本来选择合适的联接算法。
如何控制优化器使用 Merge Join
最直接的控制手段就是通过 hint 指定联接算法,可以通过使用 USE_MERGE 指示优化器使用 Merge Join 算法。通常还需要配合使用 LEADING Hint,因为指定 Merge Join 算法之后计划的成本可能不是最低的,会被其他成本更低的计划(联接次序不同)覆盖。USE_MERGE 的参数为联接的右表。
使用示例。在默认情况下,优化器自主选择了 Hash Join 算法。
explain select 1 from t1, t2 where t1.c1 = t2.c1;
Query Plan:
======================================
|ID|OPERATOR |NAME|EST. ROWS|COST |
--------------------------------------
|0 |HASH JOIN | |99000 |194200|
|1 | TABLE SCAN|t1 |100000 |41911 |
|2 | TABLE SCAN|t2 |100000 |41911 |
======================================
Outputs & filters:
-------------------------------------
0 - output([1]), filter(nil),
equal_conds([t1.c1 = t2.c1]), other_conds(nil)
1 - output([t1.c1]), filter(nil),
access([t1.c1]), partitions(p0)
2 - output([t2.c1]), filter(nil),
access([t2.c1]), partitions(p0)
为了控制优化器使用 Merge Join 算法,我们可以使用 hint 控制。
explain select /*+leading(t1 t2) use_merge(t2)*/ 1 from t1, t2 where t1.c1 = t2.c1;
Query Plan:
======================================
|ID|OPERATOR |NAME|EST. ROWS|COST |
--------------------------------------
|0 |MERGE JOIN | |99000 |13200 |
|1 | TABLE SCAN|t1 |100000 |41911 |
|2 | TABLE SCAN|t2 |100000 |41911 |
======================================
Outputs & filters:
-------------------------------------
0 - output([1]), filter(nil),
equal_conds([t1.c1 = t2.c1]), other_conds(nil)
1 - output([t1.c1]), filter(nil),
access([t1.c1]), partitions(p0)
2 - output([t2.c1]), filter(nil),
access([t2.c1]), partitions(p0)
为了更好的使用 Merge Join 算法,在控制优化器时需要注意以下两点:
- 尽量在数据源有序的情况下选择 Merge Join。
- 不能对非等值联接使用 Merge Join 算法。