aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-08-01 19:42:46 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2018-08-01 19:42:52 -0400
commit1c2cb2744bf3d8ad751cd5cf3b347f10f48492b3 (patch)
tree78cbab7db4dacbac9f47b4c78974ba3c8f6c9184 /src/backend/optimizer
parentc40489e449ea08e154cd62fa055785873f7bdac8 (diff)
downloadpostgresql-1c2cb2744bf3d8ad751cd5cf3b347f10f48492b3.tar.gz
postgresql-1c2cb2744bf3d8ad751cd5cf3b347f10f48492b3.zip
Fix run-time partition pruning for appends with multiple source rels.
The previous coding here supposed that if run-time partitioning applied to a particular Append/MergeAppend plan, then all child plans of that node must be members of a single partitioning hierarchy. This is totally wrong, since an Append could be formed from a UNION ALL: we could have multiple hierarchies sharing the same Append, or child plans that aren't part of any hierarchy. To fix, restructure the related plan-time and execution-time data structures so that we can have a separate list or array for each partitioning hierarchy. Also track subplans that are not part of any hierarchy, and make sure they don't get pruned. Per reports from Phil Florent and others. Back-patch to v11, since the bug originated there. David Rowley, with a lot of cosmetic adjustments by me; thanks also to Amit Langote for review. Discussion: https://postgr.es/m/HE1PR03MB17068BB27404C90B5B788BCABA7B0@HE1PR03MB1706.eurprd03.prod.outlook.com
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/allpaths.c27
-rw-r--r--src/backend/optimizer/plan/createplan.c66
-rw-r--r--src/backend/optimizer/plan/planner.c1
3 files changed, 58 insertions, 36 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index f04c30af456..0e80aeb65cd 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1388,7 +1388,6 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
List *all_child_outers = NIL;
ListCell *l;
List *partitioned_rels = NIL;
- bool build_partitioned_rels = false;
double partial_rows = -1;
/* If appropriate, consider parallel append */
@@ -1413,10 +1412,11 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
if (rel->part_scheme != NULL)
{
if (IS_SIMPLE_REL(rel))
- partitioned_rels = rel->partitioned_child_rels;
+ partitioned_rels = list_make1(rel->partitioned_child_rels);
else if (IS_JOIN_REL(rel))
{
int relid = -1;
+ List *partrels = NIL;
/*
* For a partitioned joinrel, concatenate the component rels'
@@ -1430,16 +1430,16 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
component = root->simple_rel_array[relid];
Assert(component->part_scheme != NULL);
Assert(list_length(component->partitioned_child_rels) >= 1);
- partitioned_rels =
- list_concat(partitioned_rels,
+ partrels =
+ list_concat(partrels,
list_copy(component->partitioned_child_rels));
}
+
+ partitioned_rels = list_make1(partrels);
}
Assert(list_length(partitioned_rels) >= 1);
}
- else if (rel->rtekind == RTE_SUBQUERY)
- build_partitioned_rels = true;
/*
* For every non-dummy child, remember the cheapest path. Also, identify
@@ -1453,17 +1453,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. We must ensure that parents are always listed
- * before their child partitioned tables.
+ * For UNION ALLs with non-empty partitioned_child_rels, accumulate
+ * the Lists of child relations.
*/
- if (build_partitioned_rels)
- {
- List *cprels = childrel->partitioned_child_rels;
-
- partitioned_rels = list_concat(partitioned_rels,
- list_copy(cprels));
- }
+ if (rel->rtekind == RTE_SUBQUERY && childrel->partitioned_child_rels != NIL)
+ partitioned_rels = lappend(partitioned_rels,
+ childrel->partitioned_child_rels);
/*
* If child has an unparameterized cheapest-total path, add that to
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 0a0bec3bfcc..ae41c9efa07 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -124,6 +124,7 @@ static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo *root,
static Plan *create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual,
List **qual, List **indexqual, List **indexECs);
static void bitmap_subplan_mark_shared(Plan *plan);
+static List *flatten_partitioned_rels(List *partitioned_rels);
static TidScan *create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
List *tlist, List *scan_clauses);
static SubqueryScan *create_subqueryscan_plan(PlannerInfo *root,
@@ -202,7 +203,8 @@ static NamedTuplestoreScan *make_namedtuplestorescan(List *qptlist, List *qpqual
static WorkTableScan *make_worktablescan(List *qptlist, List *qpqual,
Index scanrelid, int wtParam);
static Append *make_append(List *appendplans, int first_partial_plan,
- List *tlist, List *partitioned_rels, List *partpruneinfos);
+ List *tlist, List *partitioned_rels,
+ PartitionPruneInfo *partpruneinfo);
static RecursiveUnion *make_recursive_union(List *tlist,
Plan *lefttree,
Plan *righttree,
@@ -1030,7 +1032,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
List *subplans = NIL;
ListCell *subpaths;
RelOptInfo *rel = best_path->path.parent;
- List *partpruneinfos = NIL;
+ PartitionPruneInfo *partpruneinfo = NULL;
/*
* The subpaths list could be empty, if every child was proven empty by
@@ -1070,8 +1072,8 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
/*
* If any quals exist, they may be useful to perform further partition
- * pruning during execution. Gather information needed by the executor
- * to do partition pruning.
+ * pruning during execution. Gather information needed by the executor to
+ * do partition pruning.
*/
if (enable_partition_pruning &&
rel->reloptkind == RELOPT_BASEREL &&
@@ -1093,10 +1095,11 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
}
if (prunequal != NIL)
- partpruneinfos =
- make_partition_pruneinfo(root,
+ partpruneinfo =
+ make_partition_pruneinfo(root, rel,
+ best_path->subpaths,
best_path->partitioned_rels,
- best_path->subpaths, prunequal);
+ prunequal);
}
/*
@@ -1108,7 +1111,7 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
plan = make_append(subplans, best_path->first_partial_path,
tlist, best_path->partitioned_rels,
- partpruneinfos);
+ partpruneinfo);
copy_generic_path_info(&plan->plan, (Path *) best_path);
@@ -1132,7 +1135,7 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
List *subplans = NIL;
ListCell *subpaths;
RelOptInfo *rel = best_path->path.parent;
- List *partpruneinfos = NIL;
+ PartitionPruneInfo *partpruneinfo = NULL;
/*
* We don't have the actual creation of the MergeAppend node split out
@@ -1220,8 +1223,8 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
/*
* If any quals exist, they may be useful to perform further partition
- * pruning during execution. Gather information needed by the executor
- * to do partition pruning.
+ * pruning during execution. Gather information needed by the executor to
+ * do partition pruning.
*/
if (enable_partition_pruning &&
rel->reloptkind == RELOPT_BASEREL &&
@@ -1244,14 +1247,16 @@ create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path)
}
if (prunequal != NIL)
- partpruneinfos = make_partition_pruneinfo(root,
- best_path->partitioned_rels,
- best_path->subpaths, prunequal);
+ partpruneinfo = make_partition_pruneinfo(root, rel,
+ best_path->subpaths,
+ best_path->partitioned_rels,
+ prunequal);
}
- node->partitioned_rels = best_path->partitioned_rels;
+ node->partitioned_rels =
+ flatten_partitioned_rels(best_path->partitioned_rels);
node->mergeplans = subplans;
- node->part_prune_infos = partpruneinfos;
+ node->part_prune_info = partpruneinfo;
return (Plan *) node;
}
@@ -5000,6 +5005,27 @@ bitmap_subplan_mark_shared(Plan *plan)
elog(ERROR, "unrecognized node type: %d", nodeTag(plan));
}
+/*
+ * flatten_partitioned_rels
+ * Convert List of Lists into a single List with all elements from the
+ * sub-lists.
+ */
+static List *
+flatten_partitioned_rels(List *partitioned_rels)
+{
+ List *newlist = NIL;
+ ListCell *lc;
+
+ foreach(lc, partitioned_rels)
+ {
+ List *sublist = lfirst(lc);
+
+ newlist = list_concat(newlist, list_copy(sublist));
+ }
+
+ return newlist;
+}
+
/*****************************************************************************
*
* PLAN NODE BUILDING ROUTINES
@@ -5343,7 +5369,7 @@ make_foreignscan(List *qptlist,
static Append *
make_append(List *appendplans, int first_partial_plan,
List *tlist, List *partitioned_rels,
- List *partpruneinfos)
+ PartitionPruneInfo *partpruneinfo)
{
Append *node = makeNode(Append);
Plan *plan = &node->plan;
@@ -5354,8 +5380,8 @@ make_append(List *appendplans, int first_partial_plan,
plan->righttree = NULL;
node->appendplans = appendplans;
node->first_partial_plan = first_partial_plan;
- node->partitioned_rels = partitioned_rels;
- node->part_prune_infos = partpruneinfos;
+ node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
+ node->part_prune_info = partpruneinfo;
return node;
}
@@ -6512,7 +6538,7 @@ make_modifytable(PlannerInfo *root,
node->operation = operation;
node->canSetTag = canSetTag;
node->nominalRelation = nominalRelation;
- node->partitioned_rels = partitioned_rels;
+ node->partitioned_rels = flatten_partitioned_rels(partitioned_rels);
node->partColsUpdated = partColsUpdated;
node->resultRelations = resultRelations;
node->resultRelIndex = -1; /* will be set correctly in setrefs.c */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index df4ec448cb0..fd06da98b9f 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1616,6 +1616,7 @@ inheritance_planner(PlannerInfo *root)
* contain at least one member, that is, the root parent's index.
*/
Assert(list_length(partitioned_rels) >= 1);
+ partitioned_rels = list_make1(partitioned_rels);
}
/* Create Path representing a ModifyTable to do the UPDATE/DELETE work */