From 44471a8e2f8cfafef08cd578cece517c547b5af0 Mon Sep 17 00:00:00 2001 From: amit Date: Wed, 13 Sep 2017 18:24:55 +0900 Subject: [PATCH v25 5/5] Add only unpruned partitioned child rels to partitioned_rels --- src/backend/optimizer/path/allpaths.c | 69 ++++++++++++++++------------------- src/backend/optimizer/plan/planner.c | 19 +++++++--- src/backend/optimizer/util/relnode.c | 3 ++ src/include/nodes/relation.h | 8 ++++ 4 files changed, 56 insertions(+), 43 deletions(-) diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 98d7a19dad..0adcfad958 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -878,7 +878,10 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel, Assert(IS_SIMPLE_REL(rel)); if (rte->relkind == RELKIND_PARTITIONED_TABLE) + { live_children = prune_append_rel_partitions(root, rel); + rel->live_partitioned_rels = list_make1_int(rti); + } /* * Initialize to compute size estimates for whole append relation. @@ -1358,44 +1361,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, NULL); - 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); @@ -1413,17 +1411,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, NULL); + if (childrel->part_scheme) partitioned_rels = list_concat(partitioned_rels, - list_copy(cprels)); - } + list_copy(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 740de4957d..3b26bab37b 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -5975,14 +5975,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 5b5be8fe16..ad40ac7f8b 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -159,6 +159,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent) rel->part_rels = NULL; rel->partexprs = NULL; rel->nullable_partexprs = NULL; + rel->live_partitioned_rels = NIL; /* * Pass top parent's relids down the inheritance hierarchy. If the parent @@ -574,6 +575,7 @@ build_join_rel(PlannerInfo *root, joinrel->part_rels = NULL; joinrel->partexprs = NULL; joinrel->nullable_partexprs = NULL; + joinrel->live_partitioned_rels = NIL; /* Compute information relevant to the foreign relations. */ set_foreign_rel_properties(joinrel, outer_rel, inner_rel); @@ -745,6 +747,7 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel, joinrel->part_rels = NULL; joinrel->partexprs = NULL; joinrel->nullable_partexprs = NULL; + joinrel->live_partitioned_rels = NIL; joinrel->top_parent_relids = bms_union(outer_rel->top_parent_relids, inner_rel->top_parent_relids); diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 5ee23a5bb5..6454954e3b 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -542,6 +542,8 @@ typedef struct PartitionSchemeData *PartitionScheme; * partition_qual - Partition constraint if not the root * part_rels - RelOptInfos for each partition * partexprs, nullable_partexprs - Partition key expressions + * live_partitioned_rels - RT indexes of unpruned partitions that are + * partitioned tables themselves * * Note: A base relation always has only one set of partition keys, but a join * relation may have as many sets of partition keys as the number of relations @@ -674,6 +676,12 @@ typedef struct RelOptInfo * stored in the same order of bounds */ List **partexprs; /* Non-nullable partition key expressions. */ List **nullable_partexprs; /* Nullable partition key expressions. */ + + /* + * 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