]> granicus.if.org Git - postgresql/commitdiff
Fix parallel query so it doesn't spoil row estimates above Gather.
authorRobert Haas <rhaas@postgresql.org>
Sat, 1 Apr 2017 01:01:20 +0000 (21:01 -0400)
committerRobert Haas <rhaas@postgresql.org>
Sat, 1 Apr 2017 01:01:20 +0000 (21:01 -0400)
Commit 45be99f8cd5d606086e0a458c9c72910ba8a613d removed GatherPath's
num_workers field, but this is entirely bogus.  Normally, a path's
parallel_workers flag is supposed to indicate the number of workers
that it wants, and should be 0 for a non-partial path.  In that
commit, I mistakenly thought that GatherPath could also use that field
to indicate the number of workers that it would try to start, but
that's disastrous, because then it can propagate up to higher nodes in
the plan tree, which will then get incorrect rowcounts because the
parallel_workers flag is involved in computing those values.  Repair
by putting the separate field back.

Report by Tomas Vondra.  Patch by me, reviewed by Amit Kapila.

Discussion: http://postgr.es/m/f91b4a44-f739-04bd-c4b6-f135bd643669@2ndquadrant.com

src/backend/nodes/outfuncs.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/util/pathnode.c
src/include/nodes/relation.h

index bbb63a4bfae9092dbc85bc52ab0363a4ca62a771..0b45c25a49951a925dac2e26c35b3f9b31041996 100644 (file)
@@ -1870,6 +1870,7 @@ _outGatherPath(StringInfo str, const GatherPath *node)
 
        WRITE_NODE_FIELD(subpath);
        WRITE_BOOL_FIELD(single_copy);
+       WRITE_INT_FIELD(num_workers);
 }
 
 static void
index d357479829f503c1154fb1f9ba2ee4a72f586c9e..ed06a8de7873ed71abeaa03d0454699f3ad27928 100644 (file)
@@ -1446,7 +1446,7 @@ create_gather_plan(PlannerInfo *root, GatherPath *best_path)
 
        gather_plan = make_gather(tlist,
                                                          NIL,
-                                                         best_path->path.parallel_workers,
+                                                         best_path->num_workers,
                                                          best_path->single_copy,
                                                          subplan);
 
index 999ebcee704f84749729876635b28a9b5692ef75..c6298072c9b5f3c28b8ef82c713b87e6b9bef620 100644 (file)
@@ -1742,16 +1742,17 @@ create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
                                                                                                                  required_outer);
        pathnode->path.parallel_aware = false;
        pathnode->path.parallel_safe = false;
-       pathnode->path.parallel_workers = subpath->parallel_workers;
+       pathnode->path.parallel_workers = 0;
        pathnode->path.pathkeys = NIL;          /* Gather has unordered result */
 
        pathnode->subpath = subpath;
+       pathnode->num_workers = subpath->parallel_workers;
        pathnode->single_copy = false;
 
-       if (pathnode->path.parallel_workers == 0)
+       if (pathnode->num_workers == 0)
        {
-               pathnode->path.parallel_workers = 1;
                pathnode->path.pathkeys = subpath->pathkeys;
+               pathnode->num_workers = 1;
                pathnode->single_copy = true;
        }
 
index 8930edf8264ee466c25a13cbe083c670c55f5b27..ebf9480f3773b160112443abb7f9457b6027f01f 100644 (file)
@@ -1228,6 +1228,7 @@ typedef struct GatherPath
        Path            path;
        Path       *subpath;            /* path for each worker */
        bool            single_copy;    /* don't execute path more than once */
+       int                     num_workers;    /* number of workers sought to help */
 } GatherPath;
 
 /*