mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-11-27 07:21:09 +08:00
Fix calculation of relid sets for partitionwise child joins.
Applying add_outer_joins_to_relids() to a child join doesn't actually work, even if we've built a SpecialJoinInfo specialized to the child, because that function will also compare the join's relids to elements of the main join_info_list, which only deal in regular relids not child relids. This mistake escaped detection by the existing partitionwise join tests because they didn't test any cases where add_outer_joins_to_relids() needs to add additional OJ relids (that is, any cases where join reordering per identity 3 is possible). Instead, let's apply adjust_child_relids() to the relids of the parent join. This requires minor code reordering to collect the relevant AppendRelInfo structures first, but that's work we'd do shortly anyway. Report and fix by Richard Guo; cosmetic changes by me Discussion: https://postgr.es/m/CAMbWs49NCNbyubZWgci3o=_OTY=snCfAPtMnM-32f3mm-K-Ckw@mail.gmail.com
This commit is contained in:
parent
7c7412cae3
commit
3c90dcd039
@ -1640,13 +1640,15 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
|
||||
child_rel1->relids,
|
||||
child_rel2->relids);
|
||||
|
||||
/* Build correct join relids for child join */
|
||||
child_joinrelids = bms_union(child_rel1->relids, child_rel2->relids);
|
||||
child_joinrelids = add_outer_joins_to_relids(root, child_joinrelids,
|
||||
child_sjinfo, NULL);
|
||||
|
||||
/* Find the AppendRelInfo structures */
|
||||
appinfos = find_appinfos_by_relids(root, child_joinrelids, &nappinfos);
|
||||
appinfos = find_appinfos_by_relids(root,
|
||||
bms_union(child_rel1->relids,
|
||||
child_rel2->relids),
|
||||
&nappinfos);
|
||||
|
||||
/* Build correct join relids for child join */
|
||||
child_joinrelids = adjust_child_relids(joinrel->relids,
|
||||
nappinfos, appinfos);
|
||||
|
||||
/*
|
||||
* Construct restrictions applicable to the child join from those
|
||||
|
@ -871,10 +871,19 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
|
||||
/* The parent joinrel should have consider_partitionwise_join set. */
|
||||
Assert(parent_joinrel->consider_partitionwise_join);
|
||||
|
||||
/*
|
||||
* Find the AppendRelInfo structures for the child baserels. We'll need
|
||||
* these for computing the child join's relid set, and later for mapping
|
||||
* Vars to the child rel.
|
||||
*/
|
||||
appinfos = find_appinfos_by_relids(root,
|
||||
bms_union(outer_rel->relids,
|
||||
inner_rel->relids),
|
||||
&nappinfos);
|
||||
|
||||
joinrel->reloptkind = RELOPT_OTHER_JOINREL;
|
||||
joinrel->relids = bms_union(outer_rel->relids, inner_rel->relids);
|
||||
joinrel->relids = add_outer_joins_to_relids(root, joinrel->relids, sjinfo,
|
||||
NULL);
|
||||
joinrel->relids = adjust_child_relids(parent_joinrel->relids,
|
||||
nappinfos, appinfos);
|
||||
joinrel->rows = 0;
|
||||
/* cheap startup cost is interesting iff not all tuples to be retrieved */
|
||||
joinrel->consider_startup = (root->tuple_fraction > 0);
|
||||
@ -935,9 +944,6 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
|
||||
/* Compute information relevant to foreign relations. */
|
||||
set_foreign_rel_properties(joinrel, outer_rel, inner_rel);
|
||||
|
||||
/* Compute information needed for mapping Vars to the child rel */
|
||||
appinfos = find_appinfos_by_relids(root, joinrel->relids, &nappinfos);
|
||||
|
||||
/* Set up reltarget struct */
|
||||
build_child_join_reltarget(root, parent_joinrel, joinrel,
|
||||
nappinfos, appinfos);
|
||||
|
@ -62,6 +62,52 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b =
|
||||
450 | 0450 | 450 | 0450
|
||||
(4 rows)
|
||||
|
||||
-- left outer join, 3-way
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT COUNT(*) FROM prt1 t1
|
||||
LEFT JOIN prt1 t2 ON t1.a = t2.a
|
||||
LEFT JOIN prt1 t3 ON t2.a = t3.a;
|
||||
QUERY PLAN
|
||||
--------------------------------------------------------
|
||||
Aggregate
|
||||
-> Append
|
||||
-> Hash Left Join
|
||||
Hash Cond: (t2_1.a = t3_1.a)
|
||||
-> Hash Left Join
|
||||
Hash Cond: (t1_1.a = t2_1.a)
|
||||
-> Seq Scan on prt1_p1 t1_1
|
||||
-> Hash
|
||||
-> Seq Scan on prt1_p1 t2_1
|
||||
-> Hash
|
||||
-> Seq Scan on prt1_p1 t3_1
|
||||
-> Hash Left Join
|
||||
Hash Cond: (t2_2.a = t3_2.a)
|
||||
-> Hash Left Join
|
||||
Hash Cond: (t1_2.a = t2_2.a)
|
||||
-> Seq Scan on prt1_p2 t1_2
|
||||
-> Hash
|
||||
-> Seq Scan on prt1_p2 t2_2
|
||||
-> Hash
|
||||
-> Seq Scan on prt1_p2 t3_2
|
||||
-> Hash Left Join
|
||||
Hash Cond: (t2_3.a = t3_3.a)
|
||||
-> Hash Left Join
|
||||
Hash Cond: (t1_3.a = t2_3.a)
|
||||
-> Seq Scan on prt1_p3 t1_3
|
||||
-> Hash
|
||||
-> Seq Scan on prt1_p3 t2_3
|
||||
-> Hash
|
||||
-> Seq Scan on prt1_p3 t3_3
|
||||
(29 rows)
|
||||
|
||||
SELECT COUNT(*) FROM prt1 t1
|
||||
LEFT JOIN prt1 t2 ON t1.a = t2.a
|
||||
LEFT JOIN prt1 t3 ON t2.a = t3.a;
|
||||
count
|
||||
-------
|
||||
300
|
||||
(1 row)
|
||||
|
||||
-- left outer join, with whole-row reference; partitionwise join does not apply
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
|
||||
|
@ -34,6 +34,15 @@ EXPLAIN (COSTS OFF)
|
||||
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
|
||||
SELECT t1.a, t1.c, t2.b, t2.c FROM prt1 t1, prt2 t2 WHERE t1.a = t2.b AND t1.b = 0 ORDER BY t1.a, t2.b;
|
||||
|
||||
-- left outer join, 3-way
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT COUNT(*) FROM prt1 t1
|
||||
LEFT JOIN prt1 t2 ON t1.a = t2.a
|
||||
LEFT JOIN prt1 t3 ON t2.a = t3.a;
|
||||
SELECT COUNT(*) FROM prt1 t1
|
||||
LEFT JOIN prt1 t2 ON t1.a = t2.a
|
||||
LEFT JOIN prt1 t3 ON t2.a = t3.a;
|
||||
|
||||
-- left outer join, with whole-row reference; partitionwise join does not apply
|
||||
EXPLAIN (COSTS OFF)
|
||||
SELECT t1, t2 FROM prt1 t1 LEFT JOIN prt2 t2 ON t1.a = t2.b WHERE t1.b = 0 ORDER BY t1.a, t2.b;
|
||||
|
Loading…
Reference in New Issue
Block a user