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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy