Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d25ea01

Browse files
committed
Avoid combinatorial explosion in add_child_rel_equivalences().
If an EquivalenceClass member expression includes variables from multiple appendrels, then instead of producing one substituted expression per child relation as intended, we'd create additional child expressions for combinations of children of different appendrels. This happened because the child expressions generated while considering the first appendrel were taken as sources during substitution of the second appendrel, and so on. The extra expressions are useless, and are harmless unless there are too many of them --- but if you have several appendrels with a thousand or so members each, it gets bad fast. To fix, consider only original (non-em_is_child) EC members as candidates to be expanded. This requires the ability to substitute directly from a top parent relation's Vars to those of an indirect descendant relation, but we already have that in adjust_appendrel_attrs_multilevel(). Per bug #15847 from Feike Steenbergen. This is a longstanding misbehavior, but it's only worth worrying about when there are more appendrel children than we've historically considered wise to use. So I'm not going to take the risk of back-patching this. Discussion: https://postgr.es/m/15847-ea3734094bf8ae61@postgresql.org
1 parent de87a08 commit d25ea01

File tree

1 file changed

+36
-13
lines changed

1 file changed

+36
-13
lines changed

src/backend/optimizer/path/equivclass.c

+36-13
Original file line numberDiff line numberDiff line change
@@ -2135,11 +2135,10 @@ add_child_rel_equivalences(PlannerInfo *root,
21352135
continue;
21362136

21372137
/*
2138-
* No point in searching if parent rel not mentioned in eclass; but we
2139-
* can't tell that for sure if parent rel is itself a child.
2138+
* No point in searching if child's topmost parent rel is not
2139+
* mentioned in eclass.
21402140
*/
2141-
if (parent_rel->reloptkind == RELOPT_BASEREL &&
2142-
!bms_is_subset(parent_rel->relids, cur_ec->ec_relids))
2141+
if (!bms_is_subset(child_rel->top_parent_relids, cur_ec->ec_relids))
21432142
continue;
21442143

21452144
foreach(lc2, cur_ec->ec_members)
@@ -2149,18 +2148,41 @@ add_child_rel_equivalences(PlannerInfo *root,
21492148
if (cur_em->em_is_const)
21502149
continue; /* ignore consts here */
21512150

2152-
/* Does it reference parent_rel? */
2153-
if (bms_overlap(cur_em->em_relids, parent_rel->relids))
2151+
/*
2152+
* We consider only original EC members here, not
2153+
* already-transformed child members. Otherwise, if some original
2154+
* member expression references more than one appendrel, we'd get
2155+
* an O(N^2) explosion of useless derived expressions for
2156+
* combinations of children.
2157+
*/
2158+
if (cur_em->em_is_child)
2159+
continue; /* ignore children here */
2160+
2161+
/* Does this member reference child's topmost parent rel? */
2162+
if (bms_overlap(cur_em->em_relids, child_rel->top_parent_relids))
21542163
{
21552164
/* Yes, generate transformed child version */
21562165
Expr *child_expr;
21572166
Relids new_relids;
21582167
Relids new_nullable_relids;
21592168

2160-
child_expr = (Expr *)
2161-
adjust_appendrel_attrs(root,
2162-
(Node *) cur_em->em_expr,
2163-
1, &appinfo);
2169+
if (parent_rel->reloptkind == RELOPT_BASEREL)
2170+
{
2171+
/* Simple single-level transformation */
2172+
child_expr = (Expr *)
2173+
adjust_appendrel_attrs(root,
2174+
(Node *) cur_em->em_expr,
2175+
1, &appinfo);
2176+
}
2177+
else
2178+
{
2179+
/* Must do multi-level transformation */
2180+
child_expr = (Expr *)
2181+
adjust_appendrel_attrs_multilevel(root,
2182+
(Node *) cur_em->em_expr,
2183+
child_rel->relids,
2184+
child_rel->top_parent_relids);
2185+
}
21642186

21652187
/*
21662188
* Transform em_relids to match. Note we do *not* do
@@ -2169,18 +2191,19 @@ add_child_rel_equivalences(PlannerInfo *root,
21692191
* don't want the child member to be marked as constant.
21702192
*/
21712193
new_relids = bms_difference(cur_em->em_relids,
2172-
parent_rel->relids);
2194+
child_rel->top_parent_relids);
21732195
new_relids = bms_add_members(new_relids, child_rel->relids);
21742196

21752197
/*
21762198
* And likewise for nullable_relids. Note this code assumes
21772199
* parent and child relids are singletons.
21782200
*/
21792201
new_nullable_relids = cur_em->em_nullable_relids;
2180-
if (bms_overlap(new_nullable_relids, parent_rel->relids))
2202+
if (bms_overlap(new_nullable_relids,
2203+
child_rel->top_parent_relids))
21812204
{
21822205
new_nullable_relids = bms_difference(new_nullable_relids,
2183-
parent_rel->relids);
2206+
child_rel->top_parent_relids);
21842207
new_nullable_relids = bms_add_members(new_nullable_relids,
21852208
child_rel->relids);
21862209
}

0 commit comments

Comments
 (0)