]> granicus.if.org Git - postgresql/commitdiff
Push target list evaluation through Gather Merge.
authorRobert Haas <rhaas@postgresql.org>
Mon, 13 Nov 2017 21:33:56 +0000 (16:33 -0500)
committerRobert Haas <rhaas@postgresql.org>
Mon, 13 Nov 2017 21:37:42 +0000 (16:37 -0500)
We already do this for Gather, but it got overlooked for Gather Merge.

Amit Kapila, with review and minor revisions by Rushabh Lathia
and by me.

Discussion: http://postgr.es/m/CAA4eK1KUC5Uyu7qaifxrjpHxbSeoQh3yzwN3bThnJsmJcZ-qtA@mail.gmail.com

src/backend/optimizer/plan/planner.c
src/backend/optimizer/util/pathnode.c
src/test/regress/expected/select_parallel.out
src/test/regress/sql/select_parallel.sql

index 607f7cd25187ae29999a0658199c201864d76158..90fd9cc9598a8fd36c218174de9f8aa7c59a870c 100644 (file)
@@ -5060,7 +5060,8 @@ create_ordered_paths(PlannerInfo *root,
                        path = (Path *)
                                create_gather_merge_path(root, ordered_rel,
                                                                                 path,
-                                                                                target, root->sort_pathkeys, NULL,
+                                                                                path->pathtarget,
+                                                                                root->sort_pathkeys, NULL,
                                                                                 &total_groups);
 
                        /* Add projection step if needed */
index 36ec025b05ba5b894d3ac3149e5fa141fbc2f52d..68dee0f5010b3923f13dd8f4832ac805d1b254ae 100644 (file)
@@ -2368,9 +2368,9 @@ create_projection_path(PlannerInfo *root,
  * knows that the given path isn't referenced elsewhere and so can be modified
  * in-place.
  *
- * If the input path is a GatherPath, we try to push the new target down to
- * its input as well; this is a yet more invasive modification of the input
- * path, which create_projection_path() can't do.
+ * If the input path is a GatherPath or GatherMergePath, we try to push the
+ * new target down to its input as well; this is a yet more invasive
+ * modification of the input path, which create_projection_path() can't do.
  *
  * Note that we mustn't change the source path's parent link; so when it is
  * add_path'd to "rel" things will be a bit inconsistent.  So far that has
@@ -2407,31 +2407,44 @@ apply_projection_to_path(PlannerInfo *root,
                (target->cost.per_tuple - oldcost.per_tuple) * path->rows;
 
        /*
-        * If the path happens to be a Gather path, we'd like to arrange for the
-        * subpath to return the required target list so that workers can help
-        * project.  But if there is something that is not parallel-safe in the
-        * target expressions, then we can't.
+        * If the path happens to be a Gather or GatherMerge path, we'd like to
+        * arrange for the subpath to return the required target list so that
+        * workers can help project.  But if there is something that is not
+        * parallel-safe in the target expressions, then we can't.
         */
-       if (IsA(path, GatherPath) &&
+       if ((IsA(path, GatherPath) || IsA(path, GatherMergePath)) &&
                is_parallel_safe(root, (Node *) target->exprs))
        {
-               GatherPath *gpath = (GatherPath *) path;
-
                /*
                 * We always use create_projection_path here, even if the subpath is
                 * projection-capable, so as to avoid modifying the subpath in place.
                 * It seems unlikely at present that there could be any other
                 * references to the subpath, but better safe than sorry.
                 *
-                * Note that we don't change the GatherPath's cost estimates; it might
+                * Note that we don't change the parallel path's cost estimates; it might
                 * be appropriate to do so, to reflect the fact that the bulk of the
                 * target evaluation will happen in workers.
                 */
-               gpath->subpath = (Path *)
-                       create_projection_path(root,
-                                                                  gpath->subpath->parent,
-                                                                  gpath->subpath,
-                                                                  target);
+               if (IsA(path, GatherPath))
+               {
+                       GatherPath *gpath = (GatherPath *) path;
+
+                       gpath->subpath = (Path *)
+                               create_projection_path(root,
+                                                                          gpath->subpath->parent,
+                                                                          gpath->subpath,
+                                                                          target);
+               }
+               else
+               {
+                       GatherMergePath *gmpath = (GatherMergePath *) path;
+
+                       gmpath->subpath = (Path *)
+                               create_projection_path(root,
+                                                                          gmpath->subpath->parent,
+                                                                          gmpath->subpath,
+                                                                          target);
+               }
        }
        else if (path->parallel_safe &&
                         !is_parallel_safe(root, (Node *) target->exprs))
index ac9ad0668d17c75ac8f4bd21f4613946f321b39c..6f04769e3ea0f50e67ceb797dc12d26bcb7d6306 100644 (file)
@@ -375,6 +375,31 @@ select count(*) from tenk1 group by twenty;
    500
 (20 rows)
 
+--test expressions in targetlist are pushed down for gather merge
+create or replace function simple_func(var1 integer) returns integer
+as $$
+begin
+        return var1 + 10;
+end;
+$$ language plpgsql PARALLEL SAFE;
+explain (costs off, verbose)
+    select ten, simple_func(ten) from tenk1 where ten < 100 order by ten;
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Gather Merge
+   Output: ten, (simple_func(ten))
+   Workers Planned: 4
+   ->  Result
+         Output: ten, simple_func(ten)
+         ->  Sort
+               Output: ten
+               Sort Key: tenk1.ten
+               ->  Parallel Seq Scan on public.tenk1
+                     Output: ten
+                     Filter: (tenk1.ten < 100)
+(11 rows)
+
+drop function simple_func(integer);
 --test rescan behavior of gather merge
 set enable_material = false;
 explain (costs off)
index 495f0335dccd1120aa73b6c69fbf601f0c3fcd76..9c1b87abdfc87109921c3b4e3dc42c033c0cb942 100644 (file)
@@ -144,6 +144,19 @@ explain (costs off)
 
 select count(*) from tenk1 group by twenty;
 
+--test expressions in targetlist are pushed down for gather merge
+create or replace function simple_func(var1 integer) returns integer
+as $$
+begin
+        return var1 + 10;
+end;
+$$ language plpgsql PARALLEL SAFE;
+
+explain (costs off, verbose)
+    select ten, simple_func(ten) from tenk1 where ten < 100 order by ten;
+
+drop function simple_func(integer);
+
 --test rescan behavior of gather merge
 set enable_material = false;