mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-24 18:55:04 +08:00
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
This commit is contained in:
parent
5beb7881fb
commit
e42e312430
@ -128,7 +128,7 @@ static bool find_dependent_phvs_in_jointree(PlannerInfo *root,
|
|||||||
Node *node, int varno);
|
Node *node, int varno);
|
||||||
static void substitute_phv_relids(Node *node,
|
static void substitute_phv_relids(Node *node,
|
||||||
int varno, Relids subrelids);
|
int varno, Relids subrelids);
|
||||||
static void fix_append_rel_relids(List *append_rel_list, int varno,
|
static void fix_append_rel_relids(PlannerInfo *root, int varno,
|
||||||
Relids subrelids);
|
Relids subrelids);
|
||||||
static Node *find_jointree_node_for_rel(Node *jtnode, int relid);
|
static Node *find_jointree_node_for_rel(Node *jtnode, int relid);
|
||||||
|
|
||||||
@ -1232,14 +1232,14 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
|
|||||||
* already checked that this won't require introducing multiple subrelids
|
* already checked that this won't require introducing multiple subrelids
|
||||||
* into the single-slot AppendRelInfo structs.
|
* into the single-slot AppendRelInfo structs.
|
||||||
*/
|
*/
|
||||||
if (parse->hasSubLinks || root->glob->lastPHId != 0 ||
|
if (root->glob->lastPHId != 0 || root->append_rel_list)
|
||||||
root->append_rel_list)
|
|
||||||
{
|
{
|
||||||
Relids subrelids;
|
Relids subrelids;
|
||||||
|
|
||||||
subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
|
subrelids = get_relids_in_jointree((Node *) subquery->jointree, false);
|
||||||
substitute_phv_relids((Node *) parse, varno, subrelids);
|
if (root->glob->lastPHId != 0)
|
||||||
fix_append_rel_relids(root->append_rel_list, varno, subrelids);
|
substitute_phv_relids((Node *) parse, varno, subrelids);
|
||||||
|
fix_append_rel_relids(root, varno, subrelids);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1418,7 +1418,10 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Recursively apply pull_up_subqueries to the new child RTE. (We
|
* Recursively apply pull_up_subqueries to the new child RTE. (We
|
||||||
* must build the AppendRelInfo first, because this will modify it.)
|
* must build the AppendRelInfo first, because this will modify it;
|
||||||
|
* indeed, that's the only part of the upper query where Vars
|
||||||
|
* referencing childRTindex can exist at this point.)
|
||||||
|
*
|
||||||
* Note that we can pass NULL for containing-join info even if we're
|
* Note that we can pass NULL for containing-join info even if we're
|
||||||
* actually under an outer join, because the child's expressions
|
* actually under an outer join, because the child's expressions
|
||||||
* aren't going to propagate up to the join. Also, we ignore the
|
* aren't going to propagate up to the join. Also, we ignore the
|
||||||
@ -2119,6 +2122,25 @@ perform_pullup_replace_vars(PlannerInfo *root,
|
|||||||
Query *parse = root->parse;
|
Query *parse = root->parse;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we are considering an appendrel child subquery (that is, a UNION ALL
|
||||||
|
* member query that we're pulling up), then the only part of the upper
|
||||||
|
* query that could reference the child yet is the translated_vars list of
|
||||||
|
* the associated AppendRelInfo. Furthermore, we do not need to insert
|
||||||
|
* PHVs in the AppendRelInfo --- there isn't any outer join between.
|
||||||
|
*/
|
||||||
|
if (containing_appendrel)
|
||||||
|
{
|
||||||
|
bool save_need_phvs = rvcontext->need_phvs;
|
||||||
|
|
||||||
|
rvcontext->need_phvs = false;
|
||||||
|
containing_appendrel->translated_vars = (List *)
|
||||||
|
pullup_replace_vars((Node *) containing_appendrel->translated_vars,
|
||||||
|
rvcontext);
|
||||||
|
rvcontext->need_phvs = save_need_phvs;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace all of the top query's references to the subquery's outputs
|
* Replace all of the top query's references to the subquery's outputs
|
||||||
* with copies of the adjusted subtlist items, being careful not to
|
* with copies of the adjusted subtlist items, being careful not to
|
||||||
@ -2172,22 +2194,14 @@ perform_pullup_replace_vars(PlannerInfo *root,
|
|||||||
parse->havingQual = pullup_replace_vars(parse->havingQual, rvcontext);
|
parse->havingQual = pullup_replace_vars(parse->havingQual, rvcontext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace references in the translated_vars lists of appendrels. When
|
* Replace references in the translated_vars lists of appendrels.
|
||||||
* pulling up an appendrel member, we do not need PHVs in the list of the
|
|
||||||
* parent appendrel --- there isn't any outer join between. Elsewhere,
|
|
||||||
* use PHVs for safety. (This analysis could be made tighter but it seems
|
|
||||||
* unlikely to be worth much trouble.)
|
|
||||||
*/
|
*/
|
||||||
foreach(lc, root->append_rel_list)
|
foreach(lc, root->append_rel_list)
|
||||||
{
|
{
|
||||||
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
|
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
|
||||||
bool save_need_phvs = rvcontext->need_phvs;
|
|
||||||
|
|
||||||
if (appinfo == containing_appendrel)
|
|
||||||
rvcontext->need_phvs = false;
|
|
||||||
appinfo->translated_vars = (List *)
|
appinfo->translated_vars = (List *)
|
||||||
pullup_replace_vars((Node *) appinfo->translated_vars, rvcontext);
|
pullup_replace_vars((Node *) appinfo->translated_vars, rvcontext);
|
||||||
rvcontext->need_phvs = save_need_phvs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3358,7 +3372,7 @@ remove_result_refs(PlannerInfo *root, int varno, Node *newjtloc)
|
|||||||
subrelids = get_relids_in_jointree(newjtloc, false);
|
subrelids = get_relids_in_jointree(newjtloc, false);
|
||||||
Assert(!bms_is_empty(subrelids));
|
Assert(!bms_is_empty(subrelids));
|
||||||
substitute_phv_relids((Node *) root->parse, varno, subrelids);
|
substitute_phv_relids((Node *) root->parse, varno, subrelids);
|
||||||
fix_append_rel_relids(root->append_rel_list, varno, subrelids);
|
fix_append_rel_relids(root, varno, subrelids);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3577,7 +3591,7 @@ substitute_phv_relids(Node *node, int varno, Relids subrelids)
|
|||||||
* We assume we may modify the AppendRelInfo nodes in-place.
|
* We assume we may modify the AppendRelInfo nodes in-place.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
|
fix_append_rel_relids(PlannerInfo *root, int varno, Relids subrelids)
|
||||||
{
|
{
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
int subvarno = -1;
|
int subvarno = -1;
|
||||||
@ -3588,7 +3602,7 @@ fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
|
|||||||
* AppendRelInfo nodes refer to it. So compute it on first use. Note that
|
* AppendRelInfo nodes refer to it. So compute it on first use. Note that
|
||||||
* bms_singleton_member will complain if set is not singleton.
|
* bms_singleton_member will complain if set is not singleton.
|
||||||
*/
|
*/
|
||||||
foreach(l, append_rel_list)
|
foreach(l, root->append_rel_list)
|
||||||
{
|
{
|
||||||
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
|
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
|
||||||
|
|
||||||
@ -3603,8 +3617,9 @@ fix_append_rel_relids(List *append_rel_list, int varno, Relids subrelids)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Also fix up any PHVs in its translated vars */
|
/* Also fix up any PHVs in its translated vars */
|
||||||
substitute_phv_relids((Node *) appinfo->translated_vars,
|
if (root->glob->lastPHId != 0)
|
||||||
varno, subrelids);
|
substitute_phv_relids((Node *) appinfo->translated_vars,
|
||||||
|
varno, subrelids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user