1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Add parallel_leader_participation GUC.

Sometimes, for testing, it's useful to have the leader do nothing but
read tuples from workers; and it's possible that could work out better
even in production.

Thomas Munro, reviewed by Amit Kapila and by me.  A few final tweaks
by me.

Discussion: http://postgr.es/m/CAEepm=2U++Lp3bNTv2Bv_kkr5NE2pOyHhxU=G0YTa4ZhSYhHiw@mail.gmail.com
This commit is contained in:
Robert Haas
2017-11-15 08:17:29 -05:00
parent 7518049980
commit e5253fdc4f
10 changed files with 205 additions and 9 deletions

View File

@ -38,6 +38,7 @@
#include "executor/nodeSubplan.h"
#include "executor/tqueue.h"
#include "miscadmin.h"
#include "optimizer/planmain.h"
#include "pgstat.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@ -73,7 +74,8 @@ ExecInitGather(Gather *node, EState *estate, int eflags)
gatherstate->ps.ExecProcNode = ExecGather;
gatherstate->initialized = false;
gatherstate->need_to_scan_locally = !node->single_copy;
gatherstate->need_to_scan_locally =
!node->single_copy && parallel_leader_participation;
gatherstate->tuples_needed = -1;
/*
@ -193,9 +195,9 @@ ExecGather(PlanState *pstate)
node->nextreader = 0;
}
/* Run plan locally if no workers or not single-copy. */
/* Run plan locally if no workers or enabled and not single-copy. */
node->need_to_scan_locally = (node->nreaders == 0)
|| !gather->single_copy;
|| (!gather->single_copy && parallel_leader_participation);
node->initialized = true;
}

View File

@ -23,6 +23,7 @@
#include "executor/tqueue.h"
#include "lib/binaryheap.h"
#include "miscadmin.h"
#include "optimizer/planmain.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@ -233,8 +234,9 @@ ExecGatherMerge(PlanState *pstate)
}
}
/* always allow leader to participate */
node->need_to_scan_locally = true;
/* allow leader to participate if enabled or no choice */
if (parallel_leader_participation || node->nreaders == 0)
node->need_to_scan_locally = true;
node->initialized = true;
}

View File

@ -5137,7 +5137,6 @@ static double
get_parallel_divisor(Path *path)
{
double parallel_divisor = path->parallel_workers;
double leader_contribution;
/*
* Early experience with parallel query suggests that when there is only
@ -5150,9 +5149,14 @@ get_parallel_divisor(Path *path)
* its time servicing each worker, and the remainder executing the
* parallel plan.
*/
leader_contribution = 1.0 - (0.3 * path->parallel_workers);
if (leader_contribution > 0)
parallel_divisor += leader_contribution;
if (parallel_leader_participation)
{
double leader_contribution;
leader_contribution = 1.0 - (0.3 * path->parallel_workers);
if (leader_contribution > 0)
parallel_divisor += leader_contribution;
}
return parallel_divisor;
}

View File

@ -61,6 +61,7 @@
/* GUC parameters */
double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION;
int force_parallel_mode = FORCE_PARALLEL_OFF;
bool parallel_leader_participation = true;
/* Hook for plugins to get control in planner() */
planner_hook_type planner_hook = NULL;

View File

@ -1676,6 +1676,16 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
{
{"parallel_leader_participation", PGC_USERSET, RESOURCES_ASYNCHRONOUS,
gettext_noop("Controls whether Gather and Gather Merge also run subplans."),
gettext_noop("Should gather nodes also run subplans, or just gather tuples?")
},
&parallel_leader_participation,
true,
NULL, NULL, NULL
},
/* End-of-list marker */
{
{NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL

View File

@ -163,6 +163,7 @@
#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
#max_worker_processes = 8 # (change requires restart)
#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers
#parallel_leader_particulation = on
#max_parallel_workers = 8 # maximum number of max_worker_processes that
# can be used in parallel queries
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate

View File

@ -29,6 +29,7 @@ typedef enum
#define DEFAULT_CURSOR_TUPLE_FRACTION 0.1
extern double cursor_tuple_fraction;
extern int force_parallel_mode;
extern bool parallel_leader_participation;
/* query_planner callback to compute query_pathkeys */
typedef void (*query_pathkeys_callback) (PlannerInfo *root, void *extra);

View File

@ -34,6 +34,49 @@ select count(*) from a_star;
50
(1 row)
-- test with leader participation disabled
set parallel_leader_participation = off;
explain (costs off)
select count(*) from tenk1 where stringu1 = 'GRAAAA';
QUERY PLAN
---------------------------------------------------------
Finalize Aggregate
-> Gather
Workers Planned: 4
-> Partial Aggregate
-> Parallel Seq Scan on tenk1
Filter: (stringu1 = 'GRAAAA'::name)
(6 rows)
select count(*) from tenk1 where stringu1 = 'GRAAAA';
count
-------
15
(1 row)
-- test with leader participation disabled, but no workers available (so
-- the leader will have to run the plan despite the setting)
set max_parallel_workers = 0;
explain (costs off)
select count(*) from tenk1 where stringu1 = 'GRAAAA';
QUERY PLAN
---------------------------------------------------------
Finalize Aggregate
-> Gather
Workers Planned: 4
-> Partial Aggregate
-> Parallel Seq Scan on tenk1
Filter: (stringu1 = 'GRAAAA'::name)
(6 rows)
select count(*) from tenk1 where stringu1 = 'GRAAAA';
count
-------
15
(1 row)
reset max_parallel_workers;
reset parallel_leader_participation;
-- test that parallel_restricted function doesn't run in worker
alter table tenk1 set (parallel_workers = 4);
explain (verbose, costs off)
@ -400,6 +443,49 @@ explain (costs off, verbose)
(11 rows)
drop function simple_func(integer);
-- test gather merge with parallel leader participation disabled
set parallel_leader_participation = off;
explain (costs off)
select count(*) from tenk1 group by twenty;
QUERY PLAN
----------------------------------------------------
Finalize GroupAggregate
Group Key: twenty
-> Gather Merge
Workers Planned: 4
-> Partial GroupAggregate
Group Key: twenty
-> Sort
Sort Key: twenty
-> Parallel Seq Scan on tenk1
(9 rows)
select count(*) from tenk1 group by twenty;
count
-------
500
500
500
500
500
500
500
500
500
500
500
500
500
500
500
500
500
500
500
500
(20 rows)
reset parallel_leader_participation;
--test rescan behavior of gather merge
set enable_material = false;
explain (costs off)
@ -508,6 +594,33 @@ select string4 from tenk1 order by string4 limit 5;
AAAAxx
(5 rows)
-- gather merge test with 0 workers, with parallel leader
-- participation disabled (the leader will have to run the plan
-- despite the setting)
set parallel_leader_participation = off;
explain (costs off)
select string4 from tenk1 order by string4 limit 5;
QUERY PLAN
----------------------------------------------
Limit
-> Gather Merge
Workers Planned: 4
-> Sort
Sort Key: string4
-> Parallel Seq Scan on tenk1
(6 rows)
select string4 from tenk1 order by string4 limit 5;
string4
---------
AAAAxx
AAAAxx
AAAAxx
AAAAxx
AAAAxx
(5 rows)
reset parallel_leader_participation;
reset max_parallel_workers;
SAVEPOINT settings;
SET LOCAL force_parallel_mode = 1;

View File

@ -19,6 +19,22 @@ explain (costs off)
select count(*) from a_star;
select count(*) from a_star;
-- test with leader participation disabled
set parallel_leader_participation = off;
explain (costs off)
select count(*) from tenk1 where stringu1 = 'GRAAAA';
select count(*) from tenk1 where stringu1 = 'GRAAAA';
-- test with leader participation disabled, but no workers available (so
-- the leader will have to run the plan despite the setting)
set max_parallel_workers = 0;
explain (costs off)
select count(*) from tenk1 where stringu1 = 'GRAAAA';
select count(*) from tenk1 where stringu1 = 'GRAAAA';
reset max_parallel_workers;
reset parallel_leader_participation;
-- test that parallel_restricted function doesn't run in worker
alter table tenk1 set (parallel_workers = 4);
explain (verbose, costs off)
@ -157,6 +173,16 @@ explain (costs off, verbose)
drop function simple_func(integer);
-- test gather merge with parallel leader participation disabled
set parallel_leader_participation = off;
explain (costs off)
select count(*) from tenk1 group by twenty;
select count(*) from tenk1 group by twenty;
reset parallel_leader_participation;
--test rescan behavior of gather merge
set enable_material = false;
@ -192,6 +218,16 @@ set max_parallel_workers = 0;
explain (costs off)
select string4 from tenk1 order by string4 limit 5;
select string4 from tenk1 order by string4 limit 5;
-- gather merge test with 0 workers, with parallel leader
-- participation disabled (the leader will have to run the plan
-- despite the setting)
set parallel_leader_participation = off;
explain (costs off)
select string4 from tenk1 order by string4 limit 5;
select string4 from tenk1 order by string4 limit 5;
reset parallel_leader_participation;
reset max_parallel_workers;
SAVEPOINT settings;