Improve performance of adjust_appendrel_attrs_multilevel.

The present implementations of adjust_appendrel_attrs_multilevel and
its sibling adjust_child_relids_multilevel are very messy, because
they work by reconstructing the relids of the child's immediate
parent and then seeing if that's bms_equal to the relids of the
target parent.  Aside from being quite inefficient, this will not
work with planned future changes to make joinrels' relid sets
contain outer-join relids in addition to baserels.

The whole thing can be solved at a stroke by adding explicit parent
and top_parent links to child RelOptInfos, and making these functions
work with RelOptInfo pointers instead of relids.  Doing that is
simpler for most callers, too.

In my original version of this patch, I got rid of
RelOptInfo.top_parent_relids on the grounds that it was now redundant.
However, that adds a lot of code churn in places that otherwise would
not need changing, and arguably the extra indirection needed to fetch
top_parent->relids in those places costs something.  So this version
leaves that field in place.

Discussion: https://postgr.es/m/553080.1657481916@sss.pgh.pa.us
This commit is contained in:
Tom Lane 2022-08-18 12:36:06 -04:00
parent ec97db399f
commit 2f17b57017
8 changed files with 85 additions and 96 deletions

View File

@ -1760,8 +1760,8 @@ generate_join_implied_equalities_broken(PlannerInfo *root,
if (IS_OTHER_REL(inner_rel) && result != NIL)
result = (List *) adjust_appendrel_attrs_multilevel(root,
(Node *) result,
inner_rel->relids,
inner_rel->top_parent_relids);
inner_rel,
inner_rel->top_parent);
return result;
}
@ -2626,8 +2626,8 @@ add_child_rel_equivalences(PlannerInfo *root,
child_expr = (Expr *)
adjust_appendrel_attrs_multilevel(root,
(Node *) cur_em->em_expr,
child_relids,
top_parent_relids);
child_rel,
child_rel->top_parent);
}
/*
@ -2768,8 +2768,8 @@ add_child_join_rel_equivalences(PlannerInfo *root,
child_expr = (Expr *)
adjust_appendrel_attrs_multilevel(root,
(Node *) cur_em->em_expr,
child_relids,
top_parent_relids);
child_joinrel,
child_joinrel->top_parent);
}
/*
@ -2791,8 +2791,8 @@ add_child_join_rel_equivalences(PlannerInfo *root,
new_nullable_relids =
adjust_child_relids_multilevel(root,
new_nullable_relids,
child_relids,
top_parent_relids);
child_joinrel,
child_joinrel->top_parent);
(void) add_eq_member(cur_ec, child_expr,
new_relids, new_nullable_relids,

View File

@ -1793,8 +1793,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
withCheckOptions = (List *)
adjust_appendrel_attrs_multilevel(root,
(Node *) withCheckOptions,
this_result_rel->relids,
top_result_rel->relids);
this_result_rel,
top_result_rel);
withCheckOptionLists = lappend(withCheckOptionLists,
withCheckOptions);
}
@ -1806,8 +1806,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
returningList = (List *)
adjust_appendrel_attrs_multilevel(root,
(Node *) returningList,
this_result_rel->relids,
top_result_rel->relids);
this_result_rel,
top_result_rel);
returningLists = lappend(returningLists,
returningList);
}
@ -1828,13 +1828,13 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
leaf_action->qual =
adjust_appendrel_attrs_multilevel(root,
(Node *) action->qual,
this_result_rel->relids,
top_result_rel->relids);
this_result_rel,
top_result_rel);
leaf_action->targetList = (List *)
adjust_appendrel_attrs_multilevel(root,
(Node *) action->targetList,
this_result_rel->relids,
top_result_rel->relids);
this_result_rel,
top_result_rel);
if (leaf_action->commandType == CMD_UPDATE)
leaf_action->updateColnos =
adjust_inherited_attnums_multilevel(root,

View File

@ -479,39 +479,34 @@ adjust_appendrel_attrs_mutator(Node *node,
/*
* adjust_appendrel_attrs_multilevel
* Apply Var translations from a toplevel appendrel parent down to a child.
* Apply Var translations from an appendrel parent down to a child.
*
* In some cases we need to translate expressions referencing a parent relation
* to reference an appendrel child that's multiple levels removed from it.
* Replace Vars in the "node" expression that reference "parentrel" with
* the appropriate Vars for "childrel". childrel can be more than one
* inheritance level removed from parentrel.
*/
Node *
adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
Relids child_relids,
Relids top_parent_relids)
RelOptInfo *childrel,
RelOptInfo *parentrel)
{
AppendRelInfo **appinfos;
Bitmapset *parent_relids = NULL;
int nappinfos;
int cnt;
Assert(bms_num_members(child_relids) == bms_num_members(top_parent_relids));
appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
/* Construct relids set for the immediate parent of given child. */
for (cnt = 0; cnt < nappinfos; cnt++)
{
AppendRelInfo *appinfo = appinfos[cnt];
parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
}
/* Recurse if immediate parent is not the top parent. */
if (!bms_equal(parent_relids, top_parent_relids))
node = adjust_appendrel_attrs_multilevel(root, node, parent_relids,
top_parent_relids);
if (childrel->parent != parentrel)
{
if (childrel->parent)
node = adjust_appendrel_attrs_multilevel(root, node,
childrel->parent,
parentrel);
else
elog(ERROR, "childrel is not a child of parentrel");
}
/* Now translate for this child. */
appinfos = find_appinfos_by_relids(root, childrel->relids, &nappinfos);
/* Now translate for this child */
node = adjust_appendrel_attrs(root, node, nappinfos, appinfos);
pfree(appinfos);
@ -554,56 +549,43 @@ adjust_child_relids(Relids relids, int nappinfos, AppendRelInfo **appinfos)
}
/*
* Replace any relid present in top_parent_relids with its child in
* child_relids. Members of child_relids can be multiple levels below top
* parent in the partition hierarchy.
* Substitute child's relids for parent's relids in a Relid set.
* The childrel can be multiple inheritance levels below the parent.
*/
Relids
adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
Relids child_relids, Relids top_parent_relids)
RelOptInfo *childrel,
RelOptInfo *parentrel)
{
AppendRelInfo **appinfos;
int nappinfos;
Relids parent_relids = NULL;
Relids result;
Relids tmp_result = NULL;
int cnt;
/*
* If the given relids set doesn't contain any of the top parent relids,
* it will remain unchanged.
* If the given relids set doesn't contain any of the parent relids, it
* will remain unchanged.
*/
if (!bms_overlap(relids, top_parent_relids))
if (!bms_overlap(relids, parentrel->relids))
return relids;
appinfos = find_appinfos_by_relids(root, child_relids, &nappinfos);
/* Construct relids set for the immediate parent of the given child. */
for (cnt = 0; cnt < nappinfos; cnt++)
{
AppendRelInfo *appinfo = appinfos[cnt];
parent_relids = bms_add_member(parent_relids, appinfo->parent_relid);
}
/* Recurse if immediate parent is not the top parent. */
if (!bms_equal(parent_relids, top_parent_relids))
if (childrel->parent != parentrel)
{
tmp_result = adjust_child_relids_multilevel(root, relids,
parent_relids,
top_parent_relids);
relids = tmp_result;
if (childrel->parent)
relids = adjust_child_relids_multilevel(root, relids,
childrel->parent,
parentrel);
else
elog(ERROR, "childrel is not a child of parentrel");
}
result = adjust_child_relids(relids, nappinfos, appinfos);
/* Now translate for this child. */
appinfos = find_appinfos_by_relids(root, childrel->relids, &nappinfos);
relids = adjust_child_relids(relids, nappinfos, appinfos);
/* Free memory consumed by any intermediate result. */
if (tmp_result)
bms_free(tmp_result);
bms_free(parent_relids);
pfree(appinfos);
return result;
return relids;
}
/*
@ -694,8 +676,8 @@ get_translated_update_targetlist(PlannerInfo *root, Index relid,
*processed_tlist = (List *)
adjust_appendrel_attrs_multilevel(root,
(Node *) root->processed_tlist,
bms_make_singleton(relid),
bms_make_singleton(root->parse->resultRelation));
find_base_rel(root, relid),
find_base_rel(root, root->parse->resultRelation));
if (update_colnos)
*update_colnos =
adjust_inherited_attnums_multilevel(root, root->update_colnos,

View File

@ -4026,8 +4026,8 @@ reparameterize_path_by_child(PlannerInfo *root, Path *path,
#define ADJUST_CHILD_ATTRS(node) \
((node) = \
(List *) adjust_appendrel_attrs_multilevel(root, (Node *) (node), \
child_rel->relids, \
child_rel->top_parent_relids))
child_rel, \
child_rel->top_parent))
#define REPARAMETERIZE_CHILD_PATH(path) \
do { \
@ -4244,8 +4244,8 @@ do { \
old_ppi = new_path->param_info;
required_outer =
adjust_child_relids_multilevel(root, old_ppi->ppi_req_outer,
child_rel->relids,
child_rel->top_parent_relids);
child_rel,
child_rel->top_parent);
/* If we already have a PPI for this parameterization, just return it */
new_ppi = find_param_path_info(new_path->parent, required_outer);

View File

@ -265,14 +265,10 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
*/
if (parent)
{
/*
* Each direct or indirect child wants to know the relids of its
* topmost parent.
*/
if (parent->top_parent_relids)
rel->top_parent_relids = parent->top_parent_relids;
else
rel->top_parent_relids = bms_copy(parent->relids);
/* We keep back-links to immediate parent and topmost parent. */
rel->parent = parent;
rel->top_parent = parent->top_parent ? parent->top_parent : parent;
rel->top_parent_relids = rel->top_parent->relids;
/*
* Also propagate lateral-reference information from appendrel parent
@ -294,6 +290,8 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
}
else
{
rel->parent = NULL;
rel->top_parent = NULL;
rel->top_parent_relids = NULL;
rel->direct_lateral_relids = NULL;
rel->lateral_relids = NULL;
@ -663,6 +661,8 @@ build_join_rel(PlannerInfo *root,
joinrel->joininfo = NIL;
joinrel->has_eclass_joins = false;
joinrel->consider_partitionwise_join = false; /* might get changed later */
joinrel->parent = NULL;
joinrel->top_parent = NULL;
joinrel->top_parent_relids = NULL;
joinrel->part_scheme = NULL;
joinrel->nparts = -1;
@ -843,7 +843,9 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
joinrel->joininfo = NIL;
joinrel->has_eclass_joins = false;
joinrel->consider_partitionwise_join = false; /* might get changed later */
joinrel->top_parent_relids = NULL;
joinrel->parent = parent_joinrel;
joinrel->top_parent = parent_joinrel->top_parent ? parent_joinrel->top_parent : parent_joinrel;
joinrel->top_parent_relids = joinrel->top_parent->relids;
joinrel->part_scheme = NULL;
joinrel->nparts = -1;
joinrel->boundinfo = NULL;
@ -855,9 +857,6 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
joinrel->partexprs = NULL;
joinrel->nullable_partexprs = NULL;
joinrel->top_parent_relids = bms_union(outer_rel->top_parent_relids,
inner_rel->top_parent_relids);
/* Compute information relevant to foreign relations. */
set_foreign_rel_properties(joinrel, outer_rel, inner_rel);

View File

@ -529,8 +529,8 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel,
partprunequal = (List *)
adjust_appendrel_attrs_multilevel(root,
(Node *) prunequal,
subpart->relids,
targetpart->relids);
subpart,
targetpart);
}
/*

View File

@ -938,7 +938,15 @@ typedef struct RelOptInfo
*/
/* consider partitionwise join paths? (if partitioned rel) */
bool consider_partitionwise_join;
/* Relids of topmost parents (if "other" rel) */
/*
* inheritance links, if this is an otherrel (otherwise NULL):
*/
/* Immediate parent relation (dumping it would be too verbose) */
struct RelOptInfo *parent pg_node_attr(read_write_ignore);
/* Topmost parent relation (dumping it would be too verbose) */
struct RelOptInfo *top_parent pg_node_attr(read_write_ignore);
/* Relids of topmost parent (redundant, but handy) */
Relids top_parent_relids;
/*

View File

@ -23,13 +23,13 @@ extern AppendRelInfo *make_append_rel_info(Relation parentrel,
extern Node *adjust_appendrel_attrs(PlannerInfo *root, Node *node,
int nappinfos, AppendRelInfo **appinfos);
extern Node *adjust_appendrel_attrs_multilevel(PlannerInfo *root, Node *node,
Relids child_relids,
Relids top_parent_relids);
RelOptInfo *childrel,
RelOptInfo *parentrel);
extern Relids adjust_child_relids(Relids relids, int nappinfos,
AppendRelInfo **appinfos);
extern Relids adjust_child_relids_multilevel(PlannerInfo *root, Relids relids,
Relids child_relids,
Relids top_parent_relids);
RelOptInfo *childrel,
RelOptInfo *parentrel);
extern List *adjust_inherited_attnums(List *attnums, AppendRelInfo *context);
extern List *adjust_inherited_attnums_multilevel(PlannerInfo *root,
List *attnums,