diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 72b5920..7c0ff10 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2006,14 +2006,16 @@ include_dir 'conf.d'
- Sets the maximum number of workers that can be started for an
- individual parallel operation. Parallel workers are taken from the
- pool of processes established by
- . Note that the requested
+ Sets the maximum number of processes that can be used to perform a
+ parallel operation. The leader is included, so a value of 1 disables
+ parallel query execution, and any higher value will potentially
+ attempt to launch a number of parallel workers one less than the
+ configured value. Parallel workers are taken from the pool of
+ processes established by
+ . Note that the necessary
number of workers may not actually be available at runtime. If this
occurs, the plan will run with fewer workers than expected, which may
- be inefficient. The default value is 2. Setting this value to 0
- disables parallel query execution.
+ be inefficient. The default value is 3.
diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml
index d1807ed..832afef 100644
--- a/doc/src/sgml/ref/create_table.sgml
+++ b/doc/src/sgml/ref/create_table.sgml
@@ -912,11 +912,15 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
parallel_degree> (integer>)
- The parallel degree for a table is the number of workers that should
- be used to assist a parallel scan of that table. If not set, the
+ The parallel degree for a table is the number of processes that should
+ be used for parallel scan of that table. If not set, the
system will determine a value based on the relation size. The actual
- number of workers chosen by the planner may be less, for example due to
- the setting of .
+ degree of parallelism chosen by the planner may be less, for example due
+ to the setting of . Note that
+ the leader is included, so a value of 1 indicates that a parallel scan
+ should never be used on this table. Any larger number indicates that
+ the leader and a number of workers up to one less that the configured
+ value should be used.
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 7448c7f..0163f29 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -271,11 +271,11 @@ static relopt_int intRelOpts[] =
{
{
"parallel_degree",
- "Number of parallel processes that can be used per executor node for this relation.",
+ "Number of processes that should be used for a parallel scan of this relation.",
RELOPT_KIND_HEAP,
AccessExclusiveLock
},
- -1, 0, 1024
+ -1, 1, 1024
},
/* list terminator */
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 873a764..0cee58a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -669,7 +669,7 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
static void
create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel)
{
- int parallel_degree = 1;
+ int parallel_degree = 2;
/*
* If the user has set the parallel_degree reloption, we decide what to do
@@ -678,10 +678,10 @@ create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel)
if (rel->rel_parallel_degree != -1)
{
/*
- * If parallel_degree = 0 is set for this relation, bail out. The
- * user does not want a parallel path for this relation.
+ * If we don't have permission to use at least two processes, then
+ * we can't generate a parallel path.
*/
- if (rel->rel_parallel_degree == 0)
+ if (rel->rel_parallel_degree < 2)
return;
/*
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 4c9d8d9..ac26974 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -113,7 +113,7 @@ int effective_cache_size = DEFAULT_EFFECTIVE_CACHE_SIZE;
Cost disable_cost = 1.0e10;
-int max_parallel_degree = 2;
+int max_parallel_degree = 3;
bool enable_seqscan = true;
bool enable_indexscan = true;
@@ -230,7 +230,7 @@ cost_seqscan(Path *path, PlannerInfo *root,
cpu_run_cost += path->pathtarget->cost.per_tuple * path->rows;
/* Adjust costing for parallelism, if used. */
- if (path->parallel_degree > 0)
+ if (path->parallel_degree > 1)
{
double parallel_divisor = path->parallel_degree;
double leader_contribution;
@@ -246,7 +246,7 @@ cost_seqscan(Path *path, PlannerInfo *root,
* estimate that the leader spends 30% of its time servicing each
* worker, and the remainder executing the parallel plan.
*/
- leader_contribution = 1.0 - (0.3 * path->parallel_degree);
+ leader_contribution = 1.0 - (0.3 * (path->parallel_degree - 1));
if (leader_contribution > 0)
parallel_divisor += leader_contribution;
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 185f062..abafc46 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -1383,7 +1383,7 @@ create_gather_plan(PlannerInfo *root, GatherPath *best_path)
gather_plan = make_gather(tlist,
NIL,
- best_path->path.parallel_degree,
+ best_path->path.parallel_degree - 1,
best_path->single_copy,
subplan);
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 75d93c0..1195e58 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -245,7 +245,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
glob->parallelModeOK = (cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
IsUnderPostmaster && dynamic_shared_memory_type != DSM_IMPL_NONE &&
parse->commandType == CMD_SELECT && !parse->hasModifyingCTE &&
- parse->utilityStmt == NULL && max_parallel_degree > 0 &&
+ parse->utilityStmt == NULL && max_parallel_degree > 1 &&
!IsParallelWorker() && !IsolationIsSerializable() &&
!has_parallel_hazard((Node *) parse, true);
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 6182b36..07f5e23 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -950,7 +950,7 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->pathtarget = rel->reltarget;
pathnode->param_info = get_baserel_parampathinfo(root, rel,
required_outer);
- pathnode->parallel_aware = parallel_degree > 0 ? true : false;
+ pathnode->parallel_aware = parallel_degree > 1 ? true : false;
pathnode->parallel_safe = rel->consider_parallel;
pathnode->parallel_degree = parallel_degree;
pathnode->pathkeys = NIL; /* seqscan has unordered result */
@@ -976,7 +976,7 @@ create_samplescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer
required_outer);
pathnode->parallel_aware = false;
pathnode->parallel_safe = rel->consider_parallel;
- pathnode->parallel_degree = 0;
+ pathnode->parallel_degree = 1;
pathnode->pathkeys = NIL; /* samplescan has unordered result */
cost_samplescan(pathnode, root, rel, pathnode->param_info);
@@ -1033,7 +1033,7 @@ create_index_path(PlannerInfo *root,
required_outer);
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = rel->consider_parallel;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = pathkeys;
/* Convert clauses to indexquals the executor can handle */
@@ -1082,7 +1082,7 @@ create_bitmap_heap_path(PlannerInfo *root,
required_outer);
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = rel->consider_parallel;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = NIL; /* always unordered */
pathnode->bitmapqual = bitmapqual;
@@ -1118,7 +1118,7 @@ create_bitmap_and_path(PlannerInfo *root,
*/
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = rel->consider_parallel;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = NIL; /* always unordered */
@@ -1154,7 +1154,7 @@ create_bitmap_or_path(PlannerInfo *root,
*/
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = rel->consider_parallel;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = NIL; /* always unordered */
@@ -1183,7 +1183,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
required_outer);
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = rel->consider_parallel;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = NIL; /* always unordered */
pathnode->tidquals = tidquals;
@@ -1274,7 +1274,7 @@ create_merge_append_path(PlannerInfo *root,
required_outer);
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = rel->consider_parallel;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = pathkeys;
pathnode->subpaths = subpaths;
@@ -1357,7 +1357,7 @@ create_result_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->path.param_info = NULL; /* there are no other rels... */
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = rel->consider_parallel;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = NIL;
pathnode->quals = resconstantqual;
@@ -1687,9 +1687,8 @@ create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
pathnode->subpath = subpath;
pathnode->single_copy = false;
- if (pathnode->path.parallel_degree == 0)
+ if (pathnode->path.parallel_degree == 1)
{
- pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = subpath->pathkeys;
pathnode->single_copy = true;
}
@@ -1745,7 +1744,7 @@ create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,
required_outer);
pathnode->parallel_aware = false;
pathnode->parallel_safe = rel->consider_parallel;
- pathnode->parallel_degree = 0;
+ pathnode->parallel_degree = 1;
pathnode->pathkeys = pathkeys;
cost_functionscan(pathnode, root, rel, pathnode->param_info);
@@ -1771,7 +1770,7 @@ create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel,
required_outer);
pathnode->parallel_aware = false;
pathnode->parallel_safe = rel->consider_parallel;
- pathnode->parallel_degree = 0;
+ pathnode->parallel_degree = 1;
pathnode->pathkeys = NIL; /* result is always unordered */
cost_valuesscan(pathnode, root, rel, pathnode->param_info);
@@ -1796,7 +1795,7 @@ create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
required_outer);
pathnode->parallel_aware = false;
pathnode->parallel_safe = rel->consider_parallel;
- pathnode->parallel_degree = 0;
+ pathnode->parallel_degree = 1;
pathnode->pathkeys = NIL; /* XXX for now, result is always unordered */
cost_ctescan(pathnode, root, rel, pathnode->param_info);
@@ -1822,7 +1821,7 @@ create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel,
required_outer);
pathnode->parallel_aware = false;
pathnode->parallel_safe = rel->consider_parallel;
- pathnode->parallel_degree = 0;
+ pathnode->parallel_degree = 1;
pathnode->pathkeys = NIL; /* result is always unordered */
/* Cost is the same as for a regular CTE scan */
@@ -1861,7 +1860,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
required_outer);
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = rel->consider_parallel;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.rows = rows;
pathnode->path.startup_cost = startup_cost;
pathnode->path.total_cost = total_cost;
@@ -2647,7 +2646,7 @@ create_minmaxagg_path(PlannerInfo *root,
pathnode->path.parallel_aware = false;
/* A MinMaxAggPath implies use of subplans, so cannot be parallel-safe */
pathnode->path.parallel_safe = false;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
/* Result is one unordered row */
pathnode->path.rows = 1;
pathnode->path.pathkeys = NIL;
@@ -2871,7 +2870,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->path.param_info = NULL;
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = false;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.rows = subpath->rows;
/*
@@ -2942,7 +2941,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
pathnode->path.param_info = NULL;
pathnode->path.parallel_aware = false;
pathnode->path.parallel_safe = false;
- pathnode->path.parallel_degree = 0;
+ pathnode->path.parallel_degree = 1;
pathnode->path.pathkeys = NIL;
/*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index e246a9c..1cb9879 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -2662,7 +2662,7 @@ static struct config_int ConfigureNamesInt[] =
NULL
},
&max_parallel_degree,
- 2, 0, 1024,
+ 3, 1, 1024,
NULL, NULL, NULL
},
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 2d2db7e..0fae058 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -167,7 +167,7 @@
#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
#max_worker_processes = 8 # (change requires restart)
-#max_parallel_degree = 2 # max number of worker processes per node
+#max_parallel_degree = 3 # max number of processes per node (inc. leader)
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate
# (change requires restart)
#backend_flush_after = 0 # 0 disables,
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 45739c3..2f4bcc6 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -522,7 +522,7 @@ typedef struct RelOptInfo
double allvisfrac;
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
- int rel_parallel_degree; /* wanted number of parallel workers */
+ int rel_parallel_degree; /* wanted degree of parallelism */
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
@@ -872,7 +872,7 @@ typedef struct Path
bool parallel_aware; /* engage parallel-aware logic? */
bool parallel_safe; /* OK to use as part of parallel plan? */
- int parallel_degree; /* desired parallel degree; 0 = not parallel */
+ int parallel_degree; /* desired parallel degree; 1 = not parallel */
/* estimated size/costs for path (see costsize.c for more info) */
double rows; /* estimated number of result tuples */
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index a0ba417..2e7db34 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -207,7 +207,7 @@ typedef struct StdRdOptions
AutoVacOpts autovacuum; /* autovacuum-related options */
bool user_catalog_table; /* use as an additional catalog
* relation */
- int parallel_degree; /* max number of parallel workers */
+ int parallel_degree; /* desired parallel degree */
} StdRdOptions;
#define HEAP_MIN_FILLFACTOR 10