From 11be7e7664e1d3d75d7aa12b3f5775f93ea7e462 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Tue, 13 Mar 2018 13:42:56 -0400
Subject: [PATCH 5/5] Remove explicit path construction logic in
 create_ordered_paths.

Instead of having create_ordered_paths build a path for an explicit
Sort and Gather Merge of the cheapest partial path, add an
explicitly-sorted path to tlist_rel.  If this path looks advantageous
from a cost point of view, the call to generate_gather_paths() for
tlist_rel will take care of building a Gather Merge path for it.

This improves the accuracy of costing for such paths because it
avoids using apply_projection_to_path, which has the disadvantage
of modifying a path in place after the cost has already been
determined.

Patch by me.
---
 src/backend/optimizer/plan/planner.c | 74 +++++++++++-------------------------
 1 file changed, 22 insertions(+), 52 deletions(-)

diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 9d33306783..f85011beef 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -1958,8 +1958,10 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 		 * If we can produce partial paths for the tlist rel, for possible use
 		 * by upper planning stages, do so.
 		 */
-		if (tlist_rel->consider_parallel)
+		if (tlist_rel->consider_parallel && current_rel->partial_pathlist)
 		{
+			Path	   *cheapest_partial_path;
+
 			/* Apply the scan/join target to each partial path */
 			foreach(lc, current_rel->partial_pathlist)
 			{
@@ -1975,6 +1977,25 @@ grouping_planner(PlannerInfo *root, bool inheritance_update,
 														  scanjoin_target);
 				add_partial_path(tlist_rel, newpath);
 			}
+
+			/* Also try explicitly sorting the cheapest path. */
+			cheapest_partial_path = linitial(current_rel->partial_pathlist);
+			if (!pathkeys_contained_in(root->query_pathkeys,
+									   cheapest_partial_path->pathkeys))
+			{
+				Path	   *path;
+
+				path = (Path *) create_projection_path(root,
+													   tlist_rel,
+													   cheapest_partial_path,
+													   scanjoin_target);
+				path = (Path *) create_sort_path(root,
+												 tlist_rel,
+												 path,
+												 root->query_pathkeys,
+												 -1);
+				add_partial_path(tlist_rel, path);
+			}
 		}
 
 		/* Now fix things up if scan/join target contains SRFs */
@@ -4706,57 +4727,6 @@ create_ordered_paths(PlannerInfo *root,
 		}
 	}
 
-	/*
-	 * generate_gather_paths() will have already generated a simple Gather
-	 * path for the best parallel path, if any, and the loop above will have
-	 * considered sorting it.  Similarly, generate_gather_paths() will also
-	 * have generated order-preserving Gather Merge plans which can be used
-	 * without sorting if they happen to match the sort_pathkeys, and the loop
-	 * above will have handled those as well.  However, there's one more
-	 * possibility: it may make sense to sort the cheapest partial path
-	 * according to the required output order and then use Gather Merge.
-	 */
-	if (ordered_rel->consider_parallel && root->sort_pathkeys != NIL &&
-		input_rel->partial_pathlist != NIL)
-	{
-		Path	   *cheapest_partial_path;
-
-		cheapest_partial_path = linitial(input_rel->partial_pathlist);
-
-		/*
-		 * If cheapest partial path doesn't need a sort, this is redundant
-		 * with what's already been tried.
-		 */
-		if (!pathkeys_contained_in(root->sort_pathkeys,
-								   cheapest_partial_path->pathkeys))
-		{
-			Path	   *path;
-			double		total_groups;
-
-			path = (Path *) create_sort_path(root,
-											 ordered_rel,
-											 cheapest_partial_path,
-											 root->sort_pathkeys,
-											 limit_tuples);
-
-			total_groups = cheapest_partial_path->rows *
-				cheapest_partial_path->parallel_workers;
-			path = (Path *)
-				create_gather_merge_path(root, ordered_rel,
-										 path,
-										 path->pathtarget,
-										 root->sort_pathkeys, NULL,
-										 &total_groups);
-
-			/* Add projection step if needed */
-			if (path->pathtarget != target)
-				path = apply_projection_to_path(root, ordered_rel,
-												path, target);
-
-			add_path(ordered_rel, path);
-		}
-	}
-
 	/*
 	 * If there is an FDW that's responsible for all baserels of the query,
 	 * let it consider adding ForeignPaths.
-- 
2.14.3 (Apple Git-98)

