Commit 8d8dcead authored by Etsuro Fujita's avatar Etsuro Fujita

Postpone generating tlists and EC members for inheritance dummy children.

Previously, in set_append_rel_size(), we generated tlists and EC members
for dummy children for possible use by partition-wise join, even if
partition-wise join was disabled or the top parent was not a partitioned
table, but adding such EC members causes noticeable planning speed
degradation for queries with certain kinds of join quals like
"(foo.x + bar.y) = constant" where foo and bar are partitioned tables in
cases where there are lots of dummy children, as the EC members lists
grow huge, especially for the ECs derived from such join quals, which
makes the search for the parent EC members in add_child_rel_equivalences()
very time-consuming.  Postpone the work until such children are actually
involved in a partition-wise join.

Reported-by: Sanyo Capobiango
Analyzed-by: Justin Pryzby and Alvaro Herrera
Author: Amit Langote, with a few additional changes by me
Reviewed-by: Ashutosh Bapat
Backpatch-through: v11 where partition-wise join was added
Discussion: https://postgr.es/m/CAO698qZnrxoZu7MEtfiJmpmUtz3AVYFVnwzR%2BpqjF%3DrmKBTgpw%40mail.gmail.com
parent 31f38174
......@@ -1018,42 +1018,11 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
/*
* Copy/Modify targetlist. Even if this child is deemed empty, we need
* its targetlist in case it falls on nullable side in a child-join
* because of partitionwise join.
*
* NB: the resulting childrel->reltarget->exprs may contain arbitrary
* expressions, which otherwise would not occur in a rel's targetlist.
* Code that might be looking at an appendrel child must cope with
* such. (Normally, a rel's targetlist would only include Vars and
* PlaceHolderVars.) XXX we do not bother to update the cost or width
* fields of childrel->reltarget; not clear if that would be useful.
*/
childrel->reltarget->exprs = (List *)
adjust_appendrel_attrs(root,
(Node *) rel->reltarget->exprs,
1, &appinfo);
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
* participates in some eclass joins (because we will want to consider
* inner-indexscan joins on the individual children) or if the parent
* has useful pathkeys (because we should try to build MergeAppend
* paths that produce those sort orderings). Even if this child is
* deemed dummy, it may fall on nullable side in a child-join, which
* in turn may participate in a MergeAppend, where we will need the
* EquivalenceClass data structures.
*/
if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
add_child_rel_equivalences(root, appinfo, rel, childrel);
childrel->has_eclass_joins = rel->has_eclass_joins;
/*
* We have to copy the parent's quals to the child, with appropriate
* substitution of variables. However, only the baserestrictinfo
* quals are needed before we can check for constraint exclusion; so
* do that first and then check to see if we can disregard this child.
* We have to copy the parent's targetlist and quals to the child,
* with appropriate substitution of variables. However, only the
* baserestrictinfo quals are needed before we can check for
* constraint exclusion; so do that first and then check to see if we
* can disregard this child.
*
* The child rel's targetlist might contain non-Var expressions, which
* means that substitution into the quals could produce opportunities
......@@ -1187,11 +1156,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
continue;
}
/* CE failed, so finish copying/modifying join quals. */
/*
* CE failed, so finish copying/modifying targetlist and join quals.
*
* NB: the resulting childrel->reltarget->exprs may contain arbitrary
* expressions, which otherwise would not occur in a rel's targetlist.
* Code that might be looking at an appendrel child must cope with
* such. (Normally, a rel's targetlist would only include Vars and
* PlaceHolderVars.) XXX we do not bother to update the cost or width
* fields of childrel->reltarget; not clear if that would be useful.
*/
childrel->joininfo = (List *)
adjust_appendrel_attrs(root,
(Node *) rel->joininfo,
1, &appinfo);
childrel->reltarget->exprs = (List *)
adjust_appendrel_attrs(root,
(Node *) rel->reltarget->exprs,
1, &appinfo);
/*
* We have to make child entries in the EquivalenceClass data
* structures as well. This is needed either if the parent
* participates in some eclass joins (because we will want to consider
* inner-indexscan joins on the individual children) or if the parent
* has useful pathkeys (because we should try to build MergeAppend
* paths that produce those sort orderings).
*/
if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
add_child_rel_equivalences(root, appinfo, rel, childrel);
childrel->has_eclass_joins = rel->has_eclass_joins;
/*
* Note: we could compute appropriate attr_needed data for the child's
......@@ -1204,9 +1198,15 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
/*
* If we consider partitionwise joins with the parent rel, do the same
* for partitioned child rels.
*
* Note: here we abuse the consider_partitionwise_join flag by setting
* it *even* for child rels that are not partitioned. In that case,
* we set it to tell try_partitionwise_join() that it doesn't need to
* generate their targetlists and EC entries as they have already been
* generated here, as opposed to the dummy child rels for which the
* flag is left set to false so that it will generate them.
*/
if (rel->consider_partitionwise_join &&
childRTE->relkind == RELKIND_PARTITIONED_TABLE)
if (rel->consider_partitionwise_join)
childrel->consider_partitionwise_join = true;
/*
......
......@@ -44,6 +44,8 @@ static void try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1,
RelOptInfo *rel2, RelOptInfo *joinrel,
SpecialJoinInfo *parent_sjinfo,
List *parent_restrictlist);
static void update_child_rel_info(PlannerInfo *root,
RelOptInfo *rel, RelOptInfo *childrel);
static SpecialJoinInfo *build_child_join_sjinfo(PlannerInfo *root,
SpecialJoinInfo *parent_sjinfo,
Relids left_relids, Relids right_relids);
......@@ -1315,6 +1317,8 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
RelOptInfo *joinrel, SpecialJoinInfo *parent_sjinfo,
List *parent_restrictlist)
{
bool rel1_is_simple = IS_SIMPLE_REL(rel1);
bool rel2_is_simple = IS_SIMPLE_REL(rel2);
int nparts;
int cnt_parts;
......@@ -1379,6 +1383,27 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
AppendRelInfo **appinfos;
int nappinfos;
/*
* If a child table has consider_partitionwise_join=false, it means
* that it's a dummy relation for which we skipped setting up tlist
* expressions and adding EC members in set_append_rel_size(), so do
* that now for use later.
*/
if (rel1_is_simple && !child_rel1->consider_partitionwise_join)
{
Assert(child_rel1->reloptkind == RELOPT_OTHER_MEMBER_REL);
Assert(IS_DUMMY_REL(child_rel1));
update_child_rel_info(root, rel1, child_rel1);
child_rel1->consider_partitionwise_join = true;
}
if (rel2_is_simple && !child_rel2->consider_partitionwise_join)
{
Assert(child_rel2->reloptkind == RELOPT_OTHER_MEMBER_REL);
Assert(IS_DUMMY_REL(child_rel2));
update_child_rel_info(root, rel2, child_rel2);
child_rel2->consider_partitionwise_join = true;
}
/* We should never try to join two overlapping sets of rels. */
Assert(!bms_overlap(child_rel1->relids, child_rel2->relids));
child_joinrelids = bms_union(child_rel1->relids, child_rel2->relids);
......@@ -1420,6 +1445,28 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
}
}
/*
* Set up tlist expressions for the childrel, and add EC members referencing
* the childrel.
*/
static void
update_child_rel_info(PlannerInfo *root,
RelOptInfo *rel, RelOptInfo *childrel)
{
AppendRelInfo *appinfo = root->append_rel_array[childrel->relid];
/* Make child tlist expressions */
childrel->reltarget->exprs = (List *)
adjust_appendrel_attrs(root,
(Node *) rel->reltarget->exprs,
1, &appinfo);
/* Make child entries in the EquivalenceClass as well */
if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
add_child_rel_equivalences(root, appinfo, rel, childrel);
childrel->has_eclass_joins = rel->has_eclass_joins;
}
/*
* Construct the SpecialJoinInfo for a child-join by translating
* SpecialJoinInfo for the join between parents. left_relids and right_relids
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment