Skip to content

Commit e42e312

Browse files
committed
Avoid O(N^2) cost when pulling up lots of UNION ALL subqueries.
perform_pullup_replace_vars() knows how to scan the whole parent query tree when we are replacing Vars during a subquery flattening operation. However, for the specific case of flattening a UNION ALL leaf query, that's mostly wasted work: the only place where relevant Vars could exist is in the AppendRelInfo that we just made for this leaf. Teaching perform_pullup_replace_vars() to just deal with that and exit is worthwhile because, if we have N such subqueries to pull up, we were spending O(N^2) work uselessly mutating the AppendRelInfos for all the other subqueries. While we're at it, avoid calling substitute_phv_relids if there are no PlaceHolderVars, and remove an obsolete check of parse->hasSubLinks. Andrey Lepikhov and Tom Lane Discussion: https://postgr.es/m/703c09a2-08f3-d2ec-b33d-dbecd62428b8@postgrespro.ru
1 parent 5beb788 commit e42e312

File tree

1 file changed

+35
-20
lines changed

1 file changed

+35
-20
lines changed

src/backend/optimizer/prep/prepjointree.c

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ static bool find_dependent_phvs_in_jointree(PlannerInfo *root,
128128
Node *node, int varno);
129129
static void substitute_phv_relids(Node *node,
130130
int varno, Relids subrelids);
131-
static void fix_append_rel_relids(List *append_rel_list, int varno,
131+
static void fix_append_rel_relids(PlannerInfo *root, int varno,
132132
Relids subrelids);
133133
static Node *find_jointree_node_for_rel(Node *jtnode, int relid);
134134

@@ -1232,14 +1232,14 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
12321232
* already checked that this won't require introducing multiple subrelids
12331233
* into the single-slot AppendRelInfo structs.
12341234
*/
1235-
if (parse->hasSubLinks || root->glob->lastPHId != 0 ||
1236-
root->append_rel_list)
1235+
if (root->glob->lastPHId != 0 || root->append_rel_list)
12371236
{
12381237
Relids subrelids;
12391238

12401239
subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
1241-
substitute_phv_relids((Node *) parse, varno, subrelids);
1242-
fix_append_rel_relids(root->append_rel_list, varno, subrelids);
1240+
if (root->glob->lastPHId != 0)
1241+
substitute_phv_relids((Node *) parse, varno, subrelids);
1242+
fix_append_rel_relids(root, varno, subrelids);
12431243
}
12441244

12451245
/*
@@ -1418,7 +1418,10 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
14181418

14191419
/*
14201420
* Recursively apply pull_up_subqueries to the new child RTE. (We
1421-
* must build the AppendRelInfo first, because this will modify it.)
1421+
* must build the AppendRelInfo first, because this will modify it;
1422+
* indeed, that's the only part of the upper query where Vars
1423+
* referencing childRTindex can exist at this point.)
1424+
*
14221425
* Note that we can pass NULL for containing-join info even if we're
14231426
* actually under an outer join, because the child's expressions
14241427
* aren't going to propagate up to the join. Also, we ignore the
@@ -2119,6 +2122,25 @@ perform_pullup_replace_vars(PlannerInfo *root,
21192122
Query *parse = root->parse;
21202123
ListCell *lc;
21212124

2125+
/*
2126+
* If we are considering an appendrel child subquery (that is, a UNION ALL
2127+
* member query that we're pulling up), then the only part of the upper
2128+
* query that could reference the child yet is the translated_vars list of
2129+
* the associated AppendRelInfo. Furthermore, we do not need to insert
2130+
* PHVs in the AppendRelInfo --- there isn't any outer join between.
2131+
*/
2132+
if (containing_appendrel)
2133+
{
2134+
bool save_need_phvs = rvcontext->need_phvs;
2135+
2136+
rvcontext->need_phvs = false;
2137+
containing_appendrel->translated_vars = (List *)
2138+
pullup_replace_vars((Node *) containing_appendrel->translated_vars,
2139+
rvcontext);
2140+
rvcontext->need_phvs = save_need_phvs;
2141+
return;
2142+
}
2143+
21222144
/*
21232145
* Replace all of the top query's references to the subquery's outputs
21242146
* with copies of the adjusted subtlist items, being careful not to
@@ -2172,22 +2194,14 @@ perform_pullup_replace_vars(PlannerInfo *root,
21722194
parse->havingQual = pullup_replace_vars(parse->havingQual, rvcontext);
21732195

21742196
/*
2175-
* Replace references in the translated_vars lists of appendrels. When
2176-
* pulling up an appendrel member, we do not need PHVs in the list of the
2177-
* parent appendrel --- there isn't any outer join between. Elsewhere,
2178-
* use PHVs for safety. (This analysis could be made tighter but it seems
2179-
* unlikely to be worth much trouble.)
2197+
* Replace references in the translated_vars lists of appendrels.
21802198
*/
21812199
foreach(lc, root->append_rel_list)
21822200
{
21832201
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
2184-
bool save_need_phvs = rvcontext->need_phvs;
21852202

2186-
if (appinfo == containing_appendrel)
2187-
rvcontext->need_phvs = false;
21882203
appinfo->translated_vars = (List *)
21892204
pullup_replace_vars((Node *) appinfo->translated_vars, rvcontext);
2190-
rvcontext->need_phvs = save_need_phvs;
21912205
}
21922206

21932207
/*
@@ -3358,7 +3372,7 @@ remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc)
33583372
subrelids = get_relids_in_jointree(newjtloc, false);
33593373
Assert(!bms_is_empty(subrelids));
33603374
substitute_phv_relids((Node *) root->parse, varno, subrelids);
3361-
fix_append_rel_relids(root->append_rel_list, varno, subrelids);
3375+
fix_append_rel_relids(root, varno, subrelids);
33623376
}
33633377

33643378
/*
@@ -3577,7 +3591,7 @@ substitute_phv_relids(Node *node, int varno, Relids subrelids)
35773591
* We assume we may modify the AppendRelInfo nodes in-place.
35783592
*/
35793593
static void
3580-
fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
3594+
fix_append_rel_relids(PlannerInfo *root, int varno, Relids subrelids)
35813595
{
35823596
ListCell *l;
35833597
int subvarno = -1;
@@ -3588,7 +3602,7 @@ fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
35883602
* AppendRelInfo nodes refer to it. So compute it on first use. Note that
35893603
* bms_singleton_member will complain if set is not singleton.
35903604
*/
3591-
foreach(l, append_rel_list)
3605+
foreach(l, root->append_rel_list)
35923606
{
35933607
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
35943608

@@ -3603,8 +3617,9 @@ fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
36033617
}
36043618

36053619
/* Also fix up any PHVs in its translated vars */
3606-
substitute_phv_relids((Node *) appinfo->translated_vars,
3607-
varno, subrelids);
3620+
if (root->glob->lastPHId != 0)
3621+
substitute_phv_relids((Node *) appinfo->translated_vars,
3622+
varno, subrelids);
36083623
}
36093624
}
36103625

0 commit comments

Comments
 (0)