0004-More-refactoring-around-partitioned-table-AppendPath-v16.patch
text/plain
Filename: 0004-More-refactoring-around-partitioned-table-AppendPath-v16.patch
Type: text/plain
Part: 3
Patch
Format: format-patch
Series: patch v16-0004
Subject: More refactoring around partitioned table AppendPath creation
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/allpaths.c | 84 | 49 |
| src/backend/optimizer/plan/planner.c | 14 | 5 |
| src/backend/optimizer/util/relnode.c | 10 | 0 |
| src/include/nodes/relation.h | 20 | 2 |
From 949c7c39d23a69a1343525b5b682f15cb51d34ff Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Wed, 13 Sep 2017 18:24:55 +0900
Subject: [PATCH 4/5] More refactoring around partitioned table AppendPath
creation
Instead of going through root->append_rel_list to pick up the child
appinfos, store them in an array called part_appinfos that stores
partition appinfos in the same order as RelOptInfos are stored in
part_rels, right when the latter are created.
Further, instead of going through root->pcinfo_list to get the list
of partitioned child rels, which ends up including even the rels
that are pruned by set_append_rel_size(), build up a list of "live"
partitioned child rels and use the same to initialize partitioned_rels
field of AppendPath.
---
src/backend/optimizer/path/allpaths.c | 133 +++++++++++++++++++++-------------
src/backend/optimizer/plan/planner.c | 19 +++--
src/backend/optimizer/util/relnode.c | 10 +++
src/include/nodes/relation.h | 22 +++++-
4 files changed, 128 insertions(+), 56 deletions(-)
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 86e7a20da9..83f79ea6cb 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -861,6 +861,7 @@ static void
set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte)
{
+ List *rel_appinfos = NIL;
int parentRTindex = rti;
bool has_live_children;
double parent_rows;
@@ -874,6 +875,27 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Assert(IS_SIMPLE_REL(rel));
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE)
+ {
+ foreach (l, root->append_rel_list)
+ {
+ AppendRelInfo *appinfo = lfirst(l);
+
+ /* append_rel_list contains all append rels; ignore others */
+ if (appinfo->parent_relid == parentRTindex)
+ rel_appinfos = lappend(rel_appinfos, appinfo);
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < rel->nparts; i++)
+ rel_appinfos = lappend(rel_appinfos, rel->part_appinfos[i]);
+
+ rel->live_partitioned_rels = list_make1_int(rti);
+ }
+
/*
* Initialize to compute size estimates for whole append relation.
*
@@ -894,7 +916,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
nattrs = rel->max_attr - rel->min_attr + 1;
parent_attrsizes = (double *) palloc0(nattrs * sizeof(double));
- foreach(l, root->append_rel_list)
+ foreach(l, rel_appinfos)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
int childRTindex;
@@ -907,10 +929,6 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
ListCell *childvars;
ListCell *lc;
- /* append_rel_list contains all append rels; ignore others */
- if (appinfo->parent_relid != parentRTindex)
- continue;
-
childRTindex = appinfo->child_relid;
childRTE = root->simple_rte_array[childRTindex];
@@ -1090,6 +1108,22 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
/* We have at least one live child. */
has_live_children = true;
+ /* Add this child as a live partition of the parent. */
+ rel->live_part_appinfos = lappend(rel->live_part_appinfos, appinfo);
+
+ /*
+ * If childrel is itself partitioned, add it and its partitioned
+ * children to the list being propagated up to the root rel. Note
+ * that rel (the parent) might just be a union all subquery, in which
+ * case, there is nothing to do here.
+ */
+ if (IS_PARTITIONED_REL(childrel) && IS_PARTITIONED_REL(rel))
+ {
+ rel->live_partitioned_rels =
+ list_concat(rel->live_partitioned_rels,
+ list_copy(childrel->live_partitioned_rels));
+ }
+
/*
* If any live child is not parallel-safe, treat the whole appendrel
* as not parallel-safe. In future we might be able to generate plans
@@ -1186,24 +1220,35 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte)
{
int parentRTindex = rti;
- List *live_childrels = NIL;
+ List *rel_appinfos = NIL,
+ *live_childrels = NIL;
ListCell *l;
+ if (rte->relkind != RELKIND_PARTITIONED_TABLE)
+ {
+ foreach (l, root->append_rel_list)
+ {
+ AppendRelInfo *appinfo = lfirst(l);
+
+ /* append_rel_list contains all append rels; ignore others */
+ if (appinfo->parent_relid == parentRTindex)
+ rel_appinfos = lappend(rel_appinfos, appinfo);
+ }
+ }
+ else
+ rel_appinfos = rel->live_part_appinfos;
+
/*
* Generate access paths for each member relation, and remember the
* non-dummy children.
*/
- foreach(l, root->append_rel_list)
+ foreach(l, rel_appinfos)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
int childRTindex;
RangeTblEntry *childRTE;
RelOptInfo *childrel;
- /* append_rel_list contains all append rels; ignore others */
- if (appinfo->parent_relid != parentRTindex)
- continue;
-
/* Re-locate the child RTE and RelOptInfo */
childRTindex = appinfo->child_relid;
childRTE = root->simple_rte_array[childRTindex];
@@ -1267,44 +1312,39 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
ListCell *l;
List *partitioned_rels = NIL;
RangeTblEntry *rte;
- bool build_partitioned_rels = false;
double partial_rows = -1;
+ /*
+ * AppendPath generated for partitioned tables must record the RT indexes
+ * of partitioned tables that are direct or indirect children of this
+ * Append rel. We can find them in rel->live_partitioned_rels. However,
+ * it contains only the immediate children, so collect those of the
+ * children that are partitioned themselves in loop below and concatenate
+ * all into one list to be passed to the path creation function.
+ *
+ * AppendPath may be for a sub-query RTE (UNION ALL), whose child sub-
+ * queries may contain references to partitioned tables. The loop below
+ * will look for such children and collect them in a list to be passed to
+ * the path creation function. (This assumes that we don't need to look
+ * through multiple levels of subquery RTEs; if we ever do, we could
+ * consider stuffing the list we generate here into sub-query RTE's
+ * RelOptInfo, just like we do for partitioned rels, which would be used
+ * when populating our parent rel with paths. For the present, that
+ * appears to be unnecessary.)
+ */
if (IS_SIMPLE_REL(rel))
{
- /*
- * A root partition will already have a PartitionedChildRelInfo, and a
- * non-root partitioned table doesn't need one, because its Append
- * paths will get flattened into the parent anyway. For a subquery
- * RTE, no PartitionedChildRelInfo exists; we collect all
- * partitioned_rels associated with any child. (This assumes that we
- * don't need to look through multiple levels of subquery RTEs; if we
- * ever do, we could create a PartitionedChildRelInfo with the
- * accumulated list of partitioned_rels which would then be found when
- * populated our parent rel with paths. For the present, that appears
- * to be unnecessary.)
- */
rte = planner_rt_fetch(rel->relid, root);
- switch (rte->rtekind)
- {
- case RTE_RELATION:
- if (rte->relkind == RELKIND_PARTITIONED_TABLE)
- partitioned_rels =
- get_partitioned_child_rels(root, rel->relid);
- break;
- case RTE_SUBQUERY:
- build_partitioned_rels = true;
- break;
- default:
- elog(ERROR, "unexpected rtekind: %d", (int) rte->rtekind);
- }
+ if (rte->rtekind == RTE_RELATION &&
+ rte->relkind == RELKIND_PARTITIONED_TABLE)
+ partitioned_rels = rel->live_partitioned_rels;
}
else if (rel->reloptkind == RELOPT_JOINREL && rel->part_scheme)
{
/*
- * Associate PartitionedChildRelInfo of the root partitioned tables
- * being joined with the root partitioned join (indicated by
- * RELOPT_JOINREL).
+ * For joinrel consisting of partitioned tables, construct the list
+ * list by combining live_partitioned_rels of the component
+ * partitioned tables, which is what the following does.
*/
partitioned_rels = get_partitioned_child_rels_for_join(root,
rel->relids);
@@ -1322,17 +1362,12 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
Path *cheapest_partial_path = NULL;
/*
- * If we need to build partitioned_rels, accumulate the partitioned
- * rels for this child.
+ * Accumulate the live partitioned children of this child, if it's
+ * itself partitioned rel.
*/
- if (build_partitioned_rels)
- {
- List *cprels;
-
- cprels = get_partitioned_child_rels(root, childrel->relid);
+ if (childrel->part_scheme)
partitioned_rels = list_concat(partitioned_rels,
- list_copy(cprels));
- }
+ childrel->live_partitioned_rels);
/*
* If child has an unparameterized cheapest-total path, add that to
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 382791fadb..ffdf9c5247 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -6189,14 +6189,23 @@ List *
get_partitioned_child_rels_for_join(PlannerInfo *root, Relids join_relids)
{
List *result = NIL;
- ListCell *l;
+ int relid;
- foreach(l, root->pcinfo_list)
+ relid = -1;
+ while ((relid = bms_next_member(join_relids, relid)) >= 0)
{
- PartitionedChildRelInfo *pc = lfirst(l);
+ RelOptInfo *rel;
- if (bms_is_member(pc->parent_relid, join_relids))
- result = list_concat(result, list_copy(pc->child_rels));
+ /* Paranoia: ignore bogus relid indexes */
+ if (relid >= root->simple_rel_array_size)
+ continue;
+ rel = root->simple_rel_array[relid];
+ if (rel == NULL)
+ continue;
+ Assert(rel->relid == relid); /* sanity check on array */
+ Assert(rel->part_scheme != NULL);
+ Assert(list_length(rel->live_partitioned_rels) >= 1);
+ result = list_concat(result, list_copy(rel->live_partitioned_rels));
}
return result;
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index daa8f516ce..dcfda1c3cc 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -154,9 +154,12 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
rel->part_scheme = NULL;
rel->nparts = 0;
rel->boundinfo = NULL;
+ rel->part_appinfos = NULL;
rel->part_rels = NULL;
rel->partexprs = NULL;
rel->nullable_partexprs = NULL;
+ rel->live_part_appinfos = NIL;
+ rel->live_partitioned_rels = NIL;
/*
* Pass top parent's relids down the inheritance hierarchy. If the parent
@@ -233,8 +236,12 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
int cnt_parts = 0;
if (nparts > 0)
+ {
+ rel->part_appinfos = (AppendRelInfo **)
+ palloc(sizeof(AppendRelInfo *) * nparts);
rel->part_rels = (RelOptInfo **)
palloc(sizeof(RelOptInfo *) * nparts);
+ }
foreach(l, root->append_rel_list)
{
@@ -258,6 +265,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
* also match the PartitionDesc. See expand_partitioned_rtentry.
*/
Assert(cnt_parts < nparts);
+ rel->part_appinfos[cnt_parts] = appinfo;
rel->part_rels[cnt_parts] = childrel;
cnt_parts++;
}
@@ -567,6 +575,7 @@ build_join_rel(PlannerInfo *root,
joinrel->part_scheme = NULL;
joinrel->nparts = 0;
joinrel->boundinfo = NULL;
+ joinrel->part_appinfos = NULL;
joinrel->part_rels = NULL;
joinrel->partexprs = NULL;
joinrel->nullable_partexprs = NULL;
@@ -734,6 +743,7 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
joinrel->has_eclass_joins = false;
joinrel->top_parent_relids = NULL;
joinrel->part_scheme = NULL;
+ joinrel->part_appinfos = NULL;
joinrel->part_rels = NULL;
joinrel->partexprs = NULL;
joinrel->nullable_partexprs = NULL;
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 1108b6a0ea..c445f401d9 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -529,6 +529,7 @@ typedef struct PartitionSchemeData *PartitionScheme;
* part_scheme - Partitioning scheme of the relation
* boundinfo - Partition bounds
* nparts - Number of partitions
+ * part_appinfos - AppendRelInfo of each partition
* part_rels - RelOptInfos for each partition
* partexprs, nullable_partexprs - Partition key expressions
*
@@ -657,10 +658,27 @@ typedef struct RelOptInfo
PartitionScheme part_scheme; /* Partitioning scheme. */
int nparts; /* number of partitions */
struct PartitionBoundInfoData *boundinfo; /* Partition bounds */
- struct RelOptInfo **part_rels; /* Array of RelOptInfos of partitions,
- * stored in the same order of bounds */
+ struct AppendRelInfo **part_appinfos; /* Array of AppendRelInfos of
+ * of partitioned, stored in the
+ * same order as of bounds */
+ struct RelOptInfo **part_rels; /* Array of RelOptInfos of *all*
+ * partitions, stored in the same order as
+ * of bounds */
List **partexprs; /* Non-nullable partition key expressions. */
List **nullable_partexprs; /* Nullable partition key expressions. */
+
+
+ /*
+ * List of AppendRelInfo's of the table's partitions that survive a
+ * query's clauses.
+ */
+ List *live_part_appinfos;
+
+ /*
+ * RT indexes of live partitions that are partitioned tables themselves.
+ * This includes the RT index of the table itself.
+ */
+ List *live_partitioned_rels;
} RelOptInfo;
/*
--
2.11.0