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