0001-Allow-direct-lookups-of-AppendRelInfo-by-child-relid.patch

application/octet-stream

Filename: 0001-Allow-direct-lookups-of-AppendRelInfo-by-child-relid.patch
Type: application/octet-stream
Part: 0
Message: Re: Performance regression with PostgreSQL 11 and partitioning

Patch

Format: format-patch
Series: patch 0001
Subject: Allow direct lookups of AppendRelInfo by child relid
File+
src/backend/optimizer/plan/planner.c 4 0
src/backend/optimizer/prep/prepunion.c 7 16
src/backend/optimizer/util/relnode.c 15 0
src/include/nodes/relation.h 4 0
From b350a734bccf679d033a6238dbafd1b834723ff3 Mon Sep 17 00:00:00 2001
From: "dgrowley@gmail.com" <dgrowley@gmail.com>
Date: Mon, 28 May 2018 14:24:09 +1200
Subject: [PATCH] Allow direct lookups of AppendRelInfo by child relid

find_appinfos_by_relids had quite a large overhead when the number of items in
the append_rel_list was high.  Here we're just looking for a single
AppendRelInfo, so let's make an array so that can be looked up directly.

A test case with 10k RANGE partitions show that planning of an UPDATE to the
partitioned table is about twice as fast with this change.
---
 src/backend/optimizer/plan/planner.c   |  4 ++++
 src/backend/optimizer/prep/prepunion.c | 23 +++++++----------------
 src/backend/optimizer/util/relnode.c   | 15 +++++++++++++++
 src/include/nodes/relation.h           |  4 ++++
 4 files changed, 30 insertions(+), 16 deletions(-)

diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 97adb270fc..db1890cdaa 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1181,6 +1181,7 @@ inheritance_planner(PlannerInfo *root)
 	List	   *final_rtable = NIL;
 	int			save_rel_array_size = 0;
 	RelOptInfo **save_rel_array = NULL;
+	AppendRelInfo **save_append_rel_array = NULL;
 	List	   *subpaths = NIL;
 	List	   *subroots = NIL;
 	List	   *resultRelations = NIL;
@@ -1590,6 +1591,7 @@ inheritance_planner(PlannerInfo *root)
 		}
 		save_rel_array_size = subroot->simple_rel_array_size;
 		save_rel_array = subroot->simple_rel_array;
+		save_append_rel_array = subroot->append_rel_array;
 
 		/* Make sure any initplans from this rel get into the outer list */
 		root->init_plans = subroot->init_plans;
@@ -1641,6 +1643,8 @@ inheritance_planner(PlannerInfo *root)
 	parse->rtable = final_rtable;
 	root->simple_rel_array_size = save_rel_array_size;
 	root->simple_rel_array = save_rel_array;
+	root->append_rel_array = save_append_rel_array;
+
 	/* Must reconstruct master's simple_rte_array, too */
 	root->simple_rte_array = (RangeTblEntry **)
 		palloc0((list_length(final_rtable) + 1) * sizeof(RangeTblEntry *));
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index eb9fe26cde..55853ed4c1 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -2703,29 +2703,20 @@ build_child_join_sjinfo(PlannerInfo *root, SpecialJoinInfo *parent_sjinfo,
 AppendRelInfo **
 find_appinfos_by_relids(PlannerInfo *root, Relids relids, int *nappinfos)
 {
-	ListCell   *lc;
 	AppendRelInfo **appinfos;
 	int			cnt = 0;
-
+	int			i;
 	*nappinfos = bms_num_members(relids);
 	appinfos = (AppendRelInfo **) palloc(sizeof(AppendRelInfo *) * *nappinfos);
 
-	foreach(lc, root->append_rel_list)
+	i = -1;
+	while ((i = bms_next_member(relids, i)) >= 0)
 	{
-		AppendRelInfo *appinfo = lfirst(lc);
+		AppendRelInfo *appinfo = root->append_rel_array[i];
 
-		if (bms_is_member(appinfo->child_relid, relids))
-		{
-			appinfos[cnt] = appinfo;
-			cnt++;
+		Assert(appinfo);
 
-			/* Stop when we have gathered all the AppendRelInfos. */
-			if (cnt == *nappinfos)
-				return appinfos;
-		}
+		appinfos[cnt++] = appinfo;
 	}
-
-	/* Should have found the entries ... */
-	elog(ERROR, "did not find all requested child rels in append_rel_list");
-	return NULL;				/* not reached */
+	return appinfos;
 }
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index 82b78420e7..7b4ea9f038 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -79,6 +79,10 @@ setup_simple_rel_arrays(PlannerInfo *root)
 	/* simple_rte_array is an array equivalent of the rtable list */
 	root->simple_rte_array = (RangeTblEntry **)
 		palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *));
+
+	root->append_rel_array = (AppendRelInfo **)
+		palloc0(root->simple_rel_array_size * sizeof(AppendRelInfo *));
+
 	rti = 1;
 	foreach(lc, root->parse->rtable)
 	{
@@ -86,6 +90,17 @@ setup_simple_rel_arrays(PlannerInfo *root)
 
 		root->simple_rte_array[rti++] = rte;
 	}
+
+	foreach(lc, root->append_rel_list)
+	{
+		AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc);
+		int		child_relid = appinfo->child_relid;
+
+		/* Sanity check */
+		Assert(child_relid < root->simple_rel_array_size);
+
+		root->append_rel_array[child_relid] = appinfo;
+	}
 }
 
 /*
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index cd2ff27656..86730cc1bc 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -151,6 +151,7 @@ typedef struct PlannerGlobal
 #define planner_subplan_get_plan(root, subplan) \
 	((Plan *) list_nth((root)->glob->subplans, (subplan)->plan_id - 1))
 
+struct AppendRelInfo;
 
 /*----------
  * PlannerInfo
@@ -201,6 +202,9 @@ typedef struct PlannerInfo
 	 */
 	RangeTblEntry **simple_rte_array;	/* rangetable as an array */
 
+	struct AppendRelInfo **append_rel_array;	/* append_rel_list indexed by
+												 * child_relid */
+
 	/*
 	 * all_baserels is a Relids set of all base relids (but not "other"
 	 * relids) in the query; that is, the Relids identifier of the final join
-- 
2.16.2.windows.1