From 8606dd19470bd956c211071a1ad6d77f0523bea0 Mon Sep 17 00:00:00 2001 From: amit Date: Mon, 4 Mar 2019 11:57:04 +0900 Subject: [PATCH v27 5/6] Teach planner to only process unpruned partitions This adds a bitmapset field live_parts to RelOptInfo and stores the partition indexes of non-dummy partitions in it, meaning it contains indexes of only those partitions that have a non-NULL RelOptInfo present in its parent's RelOptInfo's part_rels array. This speeds up processing partitioned table's partitions compared to going through the whole part_rels array in a number of places. Partitionwise join still has to visit each member of part_rels, because pruned children may fall on the nullable side of an outer join and an empty Result path must be present for building the outer join paths. --- src/backend/optimizer/path/joinrels.c | 3 +++ src/backend/optimizer/plan/planner.c | 18 +++++++++--------- src/backend/optimizer/util/inherit.c | 6 ++++++ src/backend/optimizer/util/relnode.c | 4 ++++ src/backend/partitioning/partprune.c | 18 +++++------------- src/include/nodes/pathnodes.h | 4 ++++ 6 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 39dbe8bea3..2a07fa71d5 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -1470,6 +1470,9 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2, populate_joinrel_with_paths(root, child_rel1, child_rel2, child_joinrel, child_sjinfo, child_restrictlist); + if (!IS_DUMMY_REL(child_joinrel)) + joinrel->live_parts = bms_add_member(joinrel->live_parts, + cnt_parts); } if (baserel1) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 3da2a8eab2..eaa5e18c8e 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -7134,7 +7134,9 @@ apply_scanjoin_target_to_paths(PlannerInfo *root, List *live_children = NIL; /* Adjust each partition. */ - for (partition_idx = 0; partition_idx < rel->nparts; partition_idx++) + partition_idx = -1; + while ((partition_idx = bms_next_member(rel->live_parts, + partition_idx)) >= 0) { RelOptInfo *child_rel = rel->part_rels[partition_idx]; ListCell *lc; @@ -7142,9 +7144,7 @@ apply_scanjoin_target_to_paths(PlannerInfo *root, int nappinfos; List *child_scanjoin_targets = NIL; - /* Skip processing pruned partitions. */ - if (child_rel == NULL) - continue; + Assert(child_rel != NULL); /* Translate scan/join targets for this child. */ appinfos = find_appinfos_by_relids(root, child_rel->relids, @@ -7225,7 +7225,6 @@ create_partitionwise_grouping_paths(PlannerInfo *root, PartitionwiseAggregateType patype, GroupPathExtraData *extra) { - int nparts = input_rel->nparts; int cnt_parts; List *grouped_live_children = NIL; List *partially_grouped_live_children = NIL; @@ -7237,7 +7236,9 @@ create_partitionwise_grouping_paths(PlannerInfo *root, partially_grouped_rel != NULL); /* Add paths for partitionwise aggregation/grouping. */ - for (cnt_parts = 0; cnt_parts < nparts; cnt_parts++) + cnt_parts = -1; + while ((cnt_parts = bms_next_member(input_rel->live_parts, + cnt_parts)) >= 0) { RelOptInfo *child_input_rel = input_rel->part_rels[cnt_parts]; PathTarget *child_target = copy_pathtarget(target); @@ -7247,9 +7248,8 @@ create_partitionwise_grouping_paths(PlannerInfo *root, RelOptInfo *child_grouped_rel; RelOptInfo *child_partially_grouped_rel; - /* Skip processing pruned partitions. */ - if (child_input_rel == NULL) - continue; + /* A live partition must have a RelOptInfo. */ + Assert(child_input_rel != NULL); /* Input child rel must have a path */ Assert(child_input_rel->pathlist != NIL); diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c index 4e3b2fd7e7..363129de01 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -294,6 +294,12 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte, live_parts = prune_append_rel_partitions(rel); /* + * Later steps that loop over part_rels should use these indexes + * to access unpruned partitions. + */ + rel->live_parts = live_parts; + + /* * Expand simple_rel_array and friends to hold child objects. * * We'll need nparts + 1 new slots, because we also consider parent diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 1937d0442c..0065dd6ca2 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -563,6 +563,7 @@ add_appendrel_other_rels(PlannerInfo *root, RangeTblEntry *rte, Index rti) if (childrte->relid == partdesc->oids[i]) { rel->part_rels[i] = childrel; + rel->live_parts = bms_add_member(rel->live_parts, i); break; } } @@ -1989,6 +1990,9 @@ build_joinrel_partition_info(RelOptInfo *joinrel, RelOptInfo *outer_rel, joinrel->partexprs[cnt] = partexpr; joinrel->nullable_partexprs[cnt] = nullable_partexpr; } + + /* Partitions will be added by try_partitionwise_join. */ + joinrel->live_parts = NULL; } /* diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 30ebce4e40..0f990ef6a2 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -437,29 +437,21 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, memset(subplan_map, -1, nparts * sizeof(int)); subpart_map = (int *) palloc(nparts * sizeof(int)); memset(subpart_map, -1, nparts * sizeof(int)); - present_parts = NULL; + present_parts = bms_copy(subpart->live_parts); - for (i = 0; i < nparts; i++) + i = -1; + while ((i = bms_next_member(present_parts, i)) >= 0) { RelOptInfo *partrel = subpart->part_rels[i]; int subplanidx; int subpartidx; - /* Skip processing pruned partitions. */ - if (partrel == NULL) - continue; - + Assert(partrel != NULL); subplan_map[i] = subplanidx = relid_subplan_map[partrel->relid] - 1; subpart_map[i] = subpartidx = relid_subpart_map[partrel->relid] - 1; + /* Record finding this subplan */ if (subplanidx >= 0) - { - present_parts = bms_add_member(present_parts, i); - - /* Record finding this subplan */ subplansfound = bms_add_member(subplansfound, subplanidx); - } - else if (subpartidx >= 0) - present_parts = bms_add_member(present_parts, i); } pinfo = makeNode(PartitionedRelPruneInfo); diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h index c2e292e54c..53d0485964 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -712,6 +712,10 @@ typedef struct RelOptInfo List *partition_qual; /* partition constraint */ struct RelOptInfo **part_rels; /* Array of RelOptInfos of partitions, * stored in the same order of bounds */ + Bitmapset *live_parts; /* Indexes into part_rels of the non-NULL + * RelOptInfos of unpruned partitions; exists + * to avoid having to iterate over the entire + * part_rels array to filter NULL entries. */ List **partexprs; /* Non-nullable partition key expressions. */ List **nullable_partexprs; /* Nullable partition key expressions. */ List *partitioned_child_rels; /* List of RT indexes. */ -- 2.11.0