Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit507f234

Browse files
author
Richard Guo
committed
Fix right-anti-joins when the inner relation is proven unique
For an inner_unique join, we always assume that the executor will stopscanning for matches after the first match. Therefore, for a mergejointhat is inner_unique and whose mergeclauses are sufficient to identify amatch, we set the skip_mark_restore flag to true, indicating that theexecutor need not do mark/restore calls. However, merge-right-anti-joindid not get this memo and continues scanning the inner side for matchesafter the first match. If there are duplicates in the outer scan, wemay incorrectly skip matching some inner tuples, which can lead to wrongresults.Here we fix this issue by ensuring that merge-right-anti-join alsoadvances to next outer tuple after the first match in inner_uniquecases. This also saves cycles by avoiding unnecessary scanning of innertuples after the first match.Although hash-right-anti-join does not suffer from this wrong resultsissue, we apply the same change to it as well, to help save cycles forthe same reason.Per bug #18522 from Antti Lampinen, and bug #18526 from Feliphe Pozzer.Back-patch to v16 where right-anti-join was introduced.Author: Richard GuoDiscussion:https://postgr.es/m/18522-c7a8956126afdfd0@postgresql.org
1 parent49e29cb commit507f234

File tree

4 files changed

+100
-20
lines changed

4 files changed

+100
-20
lines changed

‎src/backend/executor/nodeHashjoin.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -566,20 +566,21 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel)
566566
}
567567

568568
/*
569-
*In a right-antijoin, we never return a matched tuple.
570-
*And we need tostay on the currentouter tupleto
571-
*continue scanning the inner side for matches.
569+
*If we only need to consider the first matching inner
570+
*tuple, then advance tonextouter tupleafter we've
571+
*processed this one.
572572
*/
573-
if (node->js.jointype==JOIN_RIGHT_ANTI)
574-
continue;
573+
if (node->js.single_match)
574+
node->hj_JoinState=HJ_NEED_NEW_OUTER;
575575

576576
/*
577-
* If we only need to join to the first matching inner
578-
* tuple, then consider returning this one, but after that
579-
* continue with next outer tuple.
577+
* In a right-antijoin, we never return a matched tuple.
578+
* If it's not an inner_unique join, we need to stay on
579+
* the current outer tuple to continue scanning the inner
580+
* side for matches.
580581
*/
581-
if (node->js.single_match)
582-
node->hj_JoinState=HJ_NEED_NEW_OUTER;
582+
if (node->js.jointype==JOIN_RIGHT_ANTI)
583+
continue;
583584

584585
if (otherqual==NULL||ExecQual(otherqual,econtext))
585586
returnExecProject(node->js.ps.ps_ProjInfo);

‎src/backend/executor/nodeMergejoin.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -806,20 +806,21 @@ ExecMergeJoin(PlanState *pstate)
806806
}
807807

808808
/*
809-
*In a right-antijoin, we never return a matched tuple.
810-
*And we need tostay on the currentouter tupleto
811-
*continue scanning the inner side for matches.
809+
*If we only need to consider the first matching inner
810+
*tuple, then advance tonextouter tupleafter we've
811+
*processed this one.
812812
*/
813-
if (node->js.jointype==JOIN_RIGHT_ANTI)
814-
break;
813+
if (node->js.single_match)
814+
node->mj_JoinState=EXEC_MJ_NEXTOUTER;
815815

816816
/*
817-
* If we only need to join to the first matching inner
818-
* tuple, then consider returning this one, but after that
819-
* continue with next outer tuple.
817+
* In a right-antijoin, we never return a matched tuple.
818+
* If it's not an inner_unique join, we need to stay on
819+
* the current outer tuple to continue scanning the inner
820+
* side for matches.
820821
*/
821-
if (node->js.single_match)
822-
node->mj_JoinState=EXEC_MJ_NEXTOUTER;
822+
if (node->js.jointype==JOIN_RIGHT_ANTI)
823+
break;
823824

824825
qualResult= (otherqual==NULL||
825826
ExecQual(otherqual,econtext));

‎src/test/regress/expected/join.out

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2923,6 +2923,60 @@ select tt1.*, tt2.* from tt2 right join tt1 on tt1.joincol = tt2.joincol;
29232923
2 | | |
29242924
(3 rows)
29252925

2926+
reset enable_hashjoin;
2927+
reset enable_nestloop;
2928+
--
2929+
-- regression test for bug #18522 (merge-right-anti-join in inner_unique cases)
2930+
--
2931+
create temp table tbl_ra(a int unique, b int);
2932+
insert into tbl_ra select i, i%100 from generate_series(1,1000)i;
2933+
create index on tbl_ra (b);
2934+
analyze tbl_ra;
2935+
set enable_hashjoin to off;
2936+
set enable_nestloop to off;
2937+
-- ensure we get a merge right anti join
2938+
explain (costs off)
2939+
select * from tbl_ra t1
2940+
where not exists (select 1 from tbl_ra t2 where t2.b = t1.a) and t1.b < 2;
2941+
QUERY PLAN
2942+
-------------------------------------------------------
2943+
Merge Right Anti Join
2944+
Merge Cond: (t2.b = t1.a)
2945+
-> Index Only Scan using tbl_ra_b_idx on tbl_ra t2
2946+
-> Sort
2947+
Sort Key: t1.a
2948+
-> Bitmap Heap Scan on tbl_ra t1
2949+
Recheck Cond: (b < 2)
2950+
-> Bitmap Index Scan on tbl_ra_b_idx
2951+
Index Cond: (b < 2)
2952+
(9 rows)
2953+
2954+
-- and check we get the expected results
2955+
select * from tbl_ra t1
2956+
where not exists (select 1 from tbl_ra t2 where t2.b = t1.a) and t1.b < 2;
2957+
a | b
2958+
------+---
2959+
100 | 0
2960+
101 | 1
2961+
200 | 0
2962+
201 | 1
2963+
300 | 0
2964+
301 | 1
2965+
400 | 0
2966+
401 | 1
2967+
500 | 0
2968+
501 | 1
2969+
600 | 0
2970+
601 | 1
2971+
700 | 0
2972+
701 | 1
2973+
800 | 0
2974+
801 | 1
2975+
900 | 0
2976+
901 | 1
2977+
1000 | 0
2978+
(19 rows)
2979+
29262980
reset enable_hashjoin;
29272981
reset enable_nestloop;
29282982
--

‎src/test/regress/sql/join.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,30 @@ select tt1.*, tt2.* from tt2 right join tt1 on tt1.joincol = tt2.joincol;
693693
reset enable_hashjoin;
694694
reset enable_nestloop;
695695

696+
--
697+
-- regression test for bug #18522 (merge-right-anti-join in inner_unique cases)
698+
--
699+
700+
create temp table tbl_ra(aint unique, bint);
701+
insert into tbl_raselect i, i%100from generate_series(1,1000)i;
702+
createindexon tbl_ra (b);
703+
analyze tbl_ra;
704+
705+
set enable_hashjoin to off;
706+
set enable_nestloop to off;
707+
708+
-- ensure we get a merge right anti join
709+
explain (costs off)
710+
select*from tbl_ra t1
711+
where not exists (select1from tbl_ra t2wheret2.b=t1.a)andt1.b<2;
712+
713+
-- and check we get the expected results
714+
select*from tbl_ra t1
715+
where not exists (select1from tbl_ra t2wheret2.b=t1.a)andt1.b<2;
716+
717+
reset enable_hashjoin;
718+
reset enable_nestloop;
719+
696720
--
697721
-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
698722
--

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp