v3-0003-Only-lock-partitions-that-will-be-scanned-by-a-qu.patch

text/plain

Filename: v3-0003-Only-lock-partitions-that-will-be-scanned-by-a-qu.patch
Type: text/plain
Part: 2
Message: Re: speeding up planning with partitions

Patch

Format: format-patch
Series: patch v3-0003
Subject: Only lock partitions that will be scanned by a query
File+
src/backend/optimizer/prep/preptlist.c 70 57
src/backend/optimizer/prep/prepunion.c 8 7
src/backend/optimizer/util/relnode.c 28 8
src/include/optimizer/prep.h 5 1
From 4255d72da27982934b27da9ae5268ba1d553c2d8 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Thu, 23 Aug 2018 17:30:18 +0900
Subject: [PATCH v3 3/4] Only lock partitions that will be scanned by a query

---
 src/backend/optimizer/prep/preptlist.c | 127 ++++++++++++++++++---------------
 src/backend/optimizer/prep/prepunion.c |  15 ++--
 src/backend/optimizer/util/relnode.c   |  36 +++++++---
 src/include/optimizer/prep.h           |   6 +-
 4 files changed, 111 insertions(+), 73 deletions(-)

diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 8603feef2b..3f93e5933e 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -76,7 +76,6 @@ preprocess_targetlist(PlannerInfo *root)
 	RangeTblEntry *target_rte = NULL;
 	Relation	target_relation = NULL;
 	List	   *tlist;
-	ListCell   *lc;
 
 	/*
 	 * If there is a result relation, open it so we can look for missing
@@ -118,12 +117,78 @@ preprocess_targetlist(PlannerInfo *root)
 		tlist = expand_targetlist(tlist, command_type,
 								  result_relation, target_relation);
 
+
+	tlist = add_rowmark_columns(root, tlist, root->rowMarks);
+
 	/*
-	 * Add necessary junk columns for rowmarked rels.  These values are needed
-	 * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
-	 * rechecking.  See comments for PlanRowMark in plannodes.h.
+	 * If the query has a RETURNING list, add resjunk entries for any Vars
+	 * used in RETURNING that belong to other relations.  We need to do this
+	 * to make these Vars available for the RETURNING calculation.  Vars that
+	 * belong to the result rel don't need to be added, because they will be
+	 * made to refer to the actual heap tuple.
 	 */
-	foreach(lc, root->rowMarks)
+	if (parse->returningList && list_length(parse->rtable) > 1)
+	{
+		List	   *vars;
+		ListCell   *l;
+
+		vars = pull_var_clause((Node *) parse->returningList,
+							   PVC_RECURSE_AGGREGATES |
+							   PVC_RECURSE_WINDOWFUNCS |
+							   PVC_INCLUDE_PLACEHOLDERS);
+		foreach(l, vars)
+		{
+			Var		   *var = (Var *) lfirst(l);
+			TargetEntry *tle;
+
+			if (IsA(var, Var) &&
+				var->varno == result_relation)
+				continue;		/* don't need it */
+
+			if (tlist_member((Expr *) var, tlist))
+				continue;		/* already got it */
+
+			tle = makeTargetEntry((Expr *) var,
+								  list_length(tlist) + 1,
+								  NULL,
+								  true);
+
+			tlist = lappend(tlist, tle);
+		}
+		list_free(vars);
+	}
+
+	/*
+	 * If there's an ON CONFLICT UPDATE clause, preprocess its targetlist too
+	 * while we have the relation open.
+	 */
+	if (parse->onConflict)
+		parse->onConflict->onConflictSet =
+			expand_targetlist(parse->onConflict->onConflictSet,
+							  CMD_UPDATE,
+							  result_relation,
+							  target_relation);
+
+	if (target_relation)
+		heap_close(target_relation, NoLock);
+
+	return tlist;
+}
+
+/*
+ * add_rowmark_columns
+ *
+ * Add necessary junk columns for rowmarked rels.  These values are needed
+ * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
+ * rechecking.  See comments for PlanRowMark in plannodes.h.
+ */
+List *
+add_rowmark_columns(PlannerInfo *root, List *tlist, List *rowMarks)
+{
+	List	   *range_table = root->parse->rtable;
+	ListCell   *lc;
+
+	foreach(lc, rowMarks)
 	{
 		PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
 		Var		   *var;
@@ -183,58 +248,6 @@ preprocess_targetlist(PlannerInfo *root)
 		}
 	}
 
-	/*
-	 * If the query has a RETURNING list, add resjunk entries for any Vars
-	 * used in RETURNING that belong to other relations.  We need to do this
-	 * to make these Vars available for the RETURNING calculation.  Vars that
-	 * belong to the result rel don't need to be added, because they will be
-	 * made to refer to the actual heap tuple.
-	 */
-	if (parse->returningList && list_length(parse->rtable) > 1)
-	{
-		List	   *vars;
-		ListCell   *l;
-
-		vars = pull_var_clause((Node *) parse->returningList,
-							   PVC_RECURSE_AGGREGATES |
-							   PVC_RECURSE_WINDOWFUNCS |
-							   PVC_INCLUDE_PLACEHOLDERS);
-		foreach(l, vars)
-		{
-			Var		   *var = (Var *) lfirst(l);
-			TargetEntry *tle;
-
-			if (IsA(var, Var) &&
-				var->varno == result_relation)
-				continue;		/* don't need it */
-
-			if (tlist_member((Expr *) var, tlist))
-				continue;		/* already got it */
-
-			tle = makeTargetEntry((Expr *) var,
-								  list_length(tlist) + 1,
-								  NULL,
-								  true);
-
-			tlist = lappend(tlist, tle);
-		}
-		list_free(vars);
-	}
-
-	/*
-	 * If there's an ON CONFLICT UPDATE clause, preprocess its targetlist too
-	 * while we have the relation open.
-	 */
-	if (parse->onConflict)
-		parse->onConflict->onConflictSet =
-			expand_targetlist(parse->onConflict->onConflictSet,
-							  CMD_UPDATE,
-							  result_relation,
-							  target_relation);
-
-	if (target_relation)
-		heap_close(target_relation, NoLock);
-
 	return tlist;
 }
 
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 279f686fb0..4d9583e63b 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1555,14 +1555,15 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 		lockmode = AccessShareLock;
 
 	/* Scan for all members of inheritance set, acquire needed locks */
-	inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+	if (rte->relkind != RELKIND_PARTITIONED_TABLE)
+		inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
 
 	/*
 	 * Check that there's at least one descendant, else treat as no-child
 	 * case.  This could happen despite above has_subclass() check, if table
 	 * once had a child but no longer does.
 	 */
-	if (list_length(inhOIDs) < 2)
+	if (rte->relkind != RELKIND_PARTITIONED_TABLE && list_length(inhOIDs) < 2)
 	{
 		/* Clear flag before returning */
 		rte->inh = false;
@@ -1579,10 +1580,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 
 	/* Partitioned tables are expanded elsewhere. */
 	if (rte->relkind == RELKIND_PARTITIONED_TABLE)
-	{
-		list_free(inhOIDs);
 		return;
-	}
 
 	/*
 	 * Must open the parent relation to examine its tupdesc.  We need not lock
@@ -1602,7 +1600,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 									   RelationGetDescr(oldrelation),
 									   oldrc, childOID, NoLock,
 									   &appinfo, &childrte,
-									   &childRTindex);
+									   &childRTindex, NULL);
 		Assert(childRTindex > 1);
 		Assert(childrte != NULL);
 		Assert(appinfo != NULL);
@@ -1654,7 +1652,8 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
 							   Oid childOID, int lockmode,
 							   AppendRelInfo **appinfo_p,
 							   RangeTblEntry **childrte_p,
-							   Index *childRTindex_p)
+							   Index *childRTindex_p,
+							   PlanRowMark **child_rowmark)
 {
 	Query	   *parse = root->parse;
 	Oid			parentOID = parentrte->relid;
@@ -1807,6 +1806,8 @@ add_inheritance_child_to_query(PlannerInfo *root, RangeTblEntry *parentrte,
 		top_parentrc->allMarkTypes |= childrc->allMarkTypes;
 
 		root->rowMarks = lappend(root->rowMarks, childrc);
+		if (child_rowmark)
+			*child_rowmark = childrc;
 	}
 
 	/* Close child relations, but keep locks */
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index d73b4a8499..e98b626395 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -1808,16 +1808,18 @@ build_partition_rel(PlannerInfo *root, RelOptInfo *parent, Oid partoid)
 {
 	RangeTblEntry *parentrte = root->simple_rte_array[parent->relid];
 	RelOptInfo *result;
+	Index		rootRTindex = 0;
 	Index		partRTindex = 0;
 	RangeTblEntry *partrte = NULL;
 	AppendRelInfo *appinfo = NULL;
 	PlanRowMark *rootrc = NULL;
+	int			orig_allMarkTypes;
+	PlanRowMark *childrc = NULL;
+	int			lockmode;
 
 	/* Locate the root partitioned table and fetch its PlanRowMark, if any. */
 	if (root->rowMarks)
 	{
-		Index		rootRTindex = 0;
-
 		/*
 		 * The root partitioned table itself might be a child of UNION ALL
 		 * parent, so we must resort to finding the root parent like this.
@@ -1842,16 +1844,27 @@ build_partition_rel(PlannerInfo *root, RelOptInfo *parent, Oid partoid)
 		}
 
 		rootrc = get_plan_rowmark(root->rowMarks, rootRTindex);
+
+		/*
+		 * Addition of certain child rowmarks will change the value, in which
+		 * case, we need to add additional columns to the query's targetlist.
+		 */
+		if (rootrc)
+			orig_allMarkTypes = rootrc->allMarkTypes;
 	}
 
-	/*
-	 * expand_inherited_rtentry alreay locked all partitions, so pass
-	 * NoLock for lockmode.
-	 */
+	/* Determine the correct lockmode to use. */
+	if (rootRTindex == root->parse->resultRelation)
+		lockmode = RowExclusiveLock;
+	else if (rootrc && RowMarkRequiresRowShareLock(rootrc->markType))
+		lockmode = RowShareLock;
+	else
+		lockmode = AccessShareLock;
 	add_inheritance_child_to_query(root, parentrte, parent->relid,
 								   parent->reltype, parent->tupdesc,
-								   rootrc, partoid, NoLock,
-								   &appinfo, &partrte, &partRTindex);
+								   rootrc, partoid, lockmode,
+								   &appinfo, &partrte, &partRTindex,
+								   &childrc);
 
 	/* Partition turned out to be a partitioned table with 0 partitions. */
 	if (partrte == NULL)
@@ -1870,6 +1883,13 @@ build_partition_rel(PlannerInfo *root, RelOptInfo *parent, Oid partoid)
 	result->lateral_relids = parent->lateral_relids;
 	result->lateral_referencers = parent->lateral_referencers;
 
+	if (rootrc && rootrc->allMarkTypes != orig_allMarkTypes)
+	{
+		List *tlist = root->parse->targetList;
+
+		tlist = add_rowmark_columns(root, tlist, list_make1(rootrc));
+	}
+
 	return result;
 }
 
diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h
index ca66f75544..ee7406e4f6 100644
--- a/src/include/optimizer/prep.h
+++ b/src/include/optimizer/prep.h
@@ -39,6 +39,9 @@ extern Expr *canonicalize_qual(Expr *qual, bool is_check);
  * prototypes for preptlist.c
  */
 extern List *preprocess_targetlist(PlannerInfo *root);
+extern List *add_rowmark_columns(PlannerInfo *root,
+								 List *tlist,
+								 List *rowMarks);
 
 extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex);
 
@@ -57,7 +60,8 @@ extern void add_inheritance_child_to_query(PlannerInfo *root,
 								Oid childOID, int lockmode,
 								AppendRelInfo **appinfo_p,
 								RangeTblEntry **childrte_p,
-								Index *childRTindex_p);
+								Index *childRTindex_p,
+								PlanRowMark **child_rowmark);
 
 extern Node *adjust_appendrel_attrs(PlannerInfo *root, Node *node,
 					   int nappinfos, AppendRelInfo **appinfos);
-- 
2.11.0