From 72e611f2a6a6208333c1ae2c8907233d958dd6de Mon Sep 17 00:00:00 2001 From: amit Date: Mon, 4 Mar 2019 11:57:04 +0900 Subject: [PATCH v33 7/8] 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 | 19 ++++++------------- src/include/nodes/pathnodes.h | 4 ++++ 6 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index 83c24a45b8..38fda5832b 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -1498,6 +1498,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 6a0246b47f..fa1b6de9d2 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -7099,7 +7099,9 @@ apply_scanjoin_target_to_paths(PlannerInfo *root, int partition_idx; /* 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]; AppendRelInfo **appinfos; @@ -7107,9 +7109,7 @@ apply_scanjoin_target_to_paths(PlannerInfo *root, List *child_scanjoin_targets = NIL; ListCell *lc; - /* 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, @@ -7189,7 +7189,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; @@ -7201,7 +7200,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); @@ -7211,9 +7212,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 5d7005de96..228fd3b339 100644 --- a/src/backend/optimizer/util/inherit.c +++ b/src/backend/optimizer/util/inherit.c @@ -284,6 +284,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 98ec918ebc..6787c33afa 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 9ebded67a9..e766555a9f 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -440,30 +440,23 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, subpart_map = (int *) palloc(nparts * sizeof(int)); memset(subpart_map, -1, nparts * sizeof(int)); relid_map = (Oid *) palloc0(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; relid_map[i] = planner_rt_fetch(partrel->relid, root)->relid; - if (subplanidx >= 0) - { - present_parts = bms_add_member(present_parts, i); - /* Record finding this subplan */ + /* Record finding this subplan */ + if (subplanidx >= 0) 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 31811f9adb..3298bd78ca 100644 --- a/src/include/nodes/pathnodes.h +++ b/src/include/nodes/pathnodes.h @@ -714,6 +714,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