Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b10e3bb

Browse files
author
Etsuro Fujita
committed
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
1 parent 0ec2978 commit b10e3bb

File tree

2 files changed

+86
-39
lines changed

2 files changed

+86
-39
lines changed

src/backend/optimizer/path/allpaths.c

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -981,42 +981,11 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
981981
Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
982982

983983
/*
984-
* Copy/Modify targetlist. Even if this child is deemed empty, we need
985-
* its targetlist in case it falls on nullable side in a child-join
986-
* because of partitionwise join.
987-
*
988-
* NB: the resulting childrel->reltarget->exprs may contain arbitrary
989-
* expressions, which otherwise would not occur in a rel's targetlist.
990-
* Code that might be looking at an appendrel child must cope with
991-
* such. (Normally, a rel's targetlist would only include Vars and
992-
* PlaceHolderVars.) XXX we do not bother to update the cost or width
993-
* fields of childrel->reltarget; not clear if that would be useful.
994-
*/
995-
childrel->reltarget->exprs = (List *)
996-
adjust_appendrel_attrs(root,
997-
(Node *) rel->reltarget->exprs,
998-
1, &appinfo);
999-
1000-
/*
1001-
* We have to make child entries in the EquivalenceClass data
1002-
* structures as well. This is needed either if the parent
1003-
* participates in some eclass joins (because we will want to consider
1004-
* inner-indexscan joins on the individual children) or if the parent
1005-
* has useful pathkeys (because we should try to build MergeAppend
1006-
* paths that produce those sort orderings). Even if this child is
1007-
* deemed dummy, it may fall on nullable side in a child-join, which
1008-
* in turn may participate in a MergeAppend, where we will need the
1009-
* EquivalenceClass data structures.
1010-
*/
1011-
if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
1012-
add_child_rel_equivalences(root, appinfo, rel, childrel);
1013-
childrel->has_eclass_joins = rel->has_eclass_joins;
1014-
1015-
/*
1016-
* We have to copy the parent's quals to the child, with appropriate
1017-
* substitution of variables. However, only the baserestrictinfo
1018-
* quals are needed before we can check for constraint exclusion; so
1019-
* do that first and then check to see if we can disregard this child.
984+
* We have to copy the parent's targetlist and quals to the child,
985+
* with appropriate substitution of variables. However, only the
986+
* baserestrictinfo quals are needed before we can check for
987+
* constraint exclusion; so do that first and then check to see if we
988+
* can disregard this child.
1020989
*
1021990
* The child rel's targetlist might contain non-Var expressions, which
1022991
* means that substitution into the quals could produce opportunities
@@ -1150,11 +1119,36 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
11501119
continue;
11511120
}
11521121

1153-
/* CE failed, so finish copying/modifying join quals. */
1122+
/*
1123+
* CE failed, so finish copying/modifying targetlist and join quals.
1124+
*
1125+
* NB: the resulting childrel->reltarget->exprs may contain arbitrary
1126+
* expressions, which otherwise would not occur in a rel's targetlist.
1127+
* Code that might be looking at an appendrel child must cope with
1128+
* such. (Normally, a rel's targetlist would only include Vars and
1129+
* PlaceHolderVars.) XXX we do not bother to update the cost or width
1130+
* fields of childrel->reltarget; not clear if that would be useful.
1131+
*/
11541132
childrel->joininfo = (List *)
11551133
adjust_appendrel_attrs(root,
11561134
(Node *) rel->joininfo,
11571135
1, &appinfo);
1136+
childrel->reltarget->exprs = (List *)
1137+
adjust_appendrel_attrs(root,
1138+
(Node *) rel->reltarget->exprs,
1139+
1, &appinfo);
1140+
1141+
/*
1142+
* We have to make child entries in the EquivalenceClass data
1143+
* structures as well. This is needed either if the parent
1144+
* participates in some eclass joins (because we will want to consider
1145+
* inner-indexscan joins on the individual children) or if the parent
1146+
* has useful pathkeys (because we should try to build MergeAppend
1147+
* paths that produce those sort orderings).
1148+
*/
1149+
if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
1150+
add_child_rel_equivalences(root, appinfo, rel, childrel);
1151+
childrel->has_eclass_joins = rel->has_eclass_joins;
11581152

11591153
/*
11601154
* Note: we could compute appropriate attr_needed data for the child's
@@ -1167,9 +1161,15 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
11671161
/*
11681162
* If we consider partitionwise joins with the parent rel, do the same
11691163
* for partitioned child rels.
1164+
*
1165+
* Note: here we abuse the consider_partitionwise_join flag by setting
1166+
* it *even* for child rels that are not partitioned. In that case,
1167+
* we set it to tell try_partitionwise_join() that it doesn't need to
1168+
* generate their targetlists and EC entries as they have already been
1169+
* generated here, as opposed to the dummy child rels for which the
1170+
* flag is left set to false so that it will generate them.
11701171
*/
1171-
if (rel->consider_partitionwise_join &&
1172-
childRTE->relkind == RELKIND_PARTITIONED_TABLE)
1172+
if (rel->consider_partitionwise_join)
11731173
childrel->consider_partitionwise_join = true;
11741174

11751175
/*

src/backend/optimizer/path/joinrels.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ static void try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1,
4444
RelOptInfo *rel2, RelOptInfo *joinrel,
4545
SpecialJoinInfo *parent_sjinfo,
4646
List *parent_restrictlist);
47+
static void update_child_rel_info(PlannerInfo *root,
48+
RelOptInfo *rel, RelOptInfo *childrel);
4749
static int match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel,
4850
bool strict_op);
4951

@@ -1312,6 +1314,8 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
13121314
RelOptInfo *joinrel, SpecialJoinInfo *parent_sjinfo,
13131315
List *parent_restrictlist)
13141316
{
1317+
bool rel1_is_simple = IS_SIMPLE_REL(rel1);
1318+
bool rel2_is_simple = IS_SIMPLE_REL(rel2);
13151319
int nparts;
13161320
int cnt_parts;
13171321

@@ -1376,6 +1380,27 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
13761380
AppendRelInfo **appinfos;
13771381
int nappinfos;
13781382

1383+
/*
1384+
* If a child table has consider_partitionwise_join=false, it means
1385+
* that it's a dummy relation for which we skipped setting up tlist
1386+
* expressions and adding EC members in set_append_rel_size(), so do
1387+
* that now for use later.
1388+
*/
1389+
if (rel1_is_simple && !child_rel1->consider_partitionwise_join)
1390+
{
1391+
Assert(child_rel1->reloptkind == RELOPT_OTHER_MEMBER_REL);
1392+
Assert(IS_DUMMY_REL(child_rel1));
1393+
update_child_rel_info(root, rel1, child_rel1);
1394+
child_rel1->consider_partitionwise_join = true;
1395+
}
1396+
if (rel2_is_simple && !child_rel2->consider_partitionwise_join)
1397+
{
1398+
Assert(child_rel2->reloptkind == RELOPT_OTHER_MEMBER_REL);
1399+
Assert(IS_DUMMY_REL(child_rel2));
1400+
update_child_rel_info(root, rel2, child_rel2);
1401+
child_rel2->consider_partitionwise_join = true;
1402+
}
1403+
13791404
/* We should never try to join two overlapping sets of rels. */
13801405
Assert(!bms_overlap(child_rel1->relids, child_rel2->relids));
13811406
child_joinrelids = bms_union(child_rel1->relids, child_rel2->relids);
@@ -1417,6 +1442,28 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
14171442
}
14181443
}
14191444

1445+
/*
1446+
* Set up tlist expressions for the childrel, and add EC members referencing
1447+
* the childrel.
1448+
*/
1449+
static void
1450+
update_child_rel_info(PlannerInfo *root,
1451+
RelOptInfo *rel, RelOptInfo *childrel)
1452+
{
1453+
AppendRelInfo *appinfo = root->append_rel_array[childrel->relid];
1454+
1455+
/* Make child tlist expressions */
1456+
childrel->reltarget->exprs = (List *)
1457+
adjust_appendrel_attrs(root,
1458+
(Node *) rel->reltarget->exprs,
1459+
1, &appinfo);
1460+
1461+
/* Make child entries in the EquivalenceClass as well */
1462+
if (rel->has_eclass_joins || has_useful_pathkeys(root, rel))
1463+
add_child_rel_equivalences(root, appinfo, rel, childrel);
1464+
childrel->has_eclass_joins = rel->has_eclass_joins;
1465+
}
1466+
14201467
/*
14211468
* Returns true if there exists an equi-join condition for each pair of
14221469
* partition keys from given relations being joined.

0 commit comments

Comments
 (0)