From 6ca81c18f136e97f3b28d3bee46457c523b0b07b Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Mon, 4 Mar 2019 11:57:04 +0900
Subject: [PATCH v31 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 55a7a34061..a549c7669b 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1497,6 +1497,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 8dd5df8cc1..2baa617f8a 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -7109,7 +7109,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;
@@ -7117,9 +7119,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,
@@ -7199,7 +7199,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;
@@ -7211,7 +7210,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);
@@ -7221,9 +7222,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
@@ -283,6 +283,12 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
 		if (partdesc->nparts > 0)
 			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.
 		 *
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 649f6c8481..dda12dca87 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -564,6 +564,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;
 				}
 			}
@@ -1990,6 +1991,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.17.2 (Apple Git-113)

