mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Determine whether it's safe to attempt a parallel plan for a query.
Commit 924bcf4f16
introduced a framework
for parallel computation in PostgreSQL that makes most but not all
built-in functions safe to execute in parallel mode. In order to have
parallel query, we'll need to be able to determine whether that query
contains functions (either built-in or user-defined) that cannot be
safely executed in parallel mode. This requires those functions to be
labeled, so this patch introduces an infrastructure for that. Some
functions currently labeled as safe may need to be revised depending on
how pending issues related to heavyweight locking under paralllelism
are resolved.
Parallel plans can't be used except for the case where the query will
run to completion. If portal execution were suspended, the parallel
mode restrictions would need to remain in effect during that time, but
that might make other queries fail. Therefore, this patch introduces
a framework that enables consideration of parallel plans only when it
is known that the plan will be run to completion. This probably needs
some refinement; for example, at bind time, we do not know whether a
query run via the extended protocol will be execution to completion or
run with a limited fetch count. Having the client indicate its
intentions at bind time would constitute a wire protocol break. Some
contexts in which parallel mode would be safe are not adjusted by this
patch; the default is not to try parallel plans except from call sites
that have been updated to say that such plans are OK.
This commit doesn't introduce any parallel paths or plans; it just
provides a way to determine whether they could potentially be used.
I'm committing it on the theory that the remaining parallel sequential
scan patches will also get committed to this release, hopefully in the
not-too-distant future.
Robert Haas and Amit Kapila. Reviewed (in earlier versions) by Noah
Misch.
This commit is contained in:
@ -19,6 +19,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "access/htup_details.h"
|
||||
#include "access/parallel.h"
|
||||
#include "executor/executor.h"
|
||||
#include "executor/nodeAgg.h"
|
||||
#include "foreign/fdwapi.h"
|
||||
@ -43,6 +44,7 @@
|
||||
#include "parser/parsetree.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "rewrite/rewriteManip.h"
|
||||
#include "storage/dsm_impl.h"
|
||||
#include "utils/rel.h"
|
||||
#include "utils/selfuncs.h"
|
||||
|
||||
@ -197,6 +199,48 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
||||
glob->transientPlan = false;
|
||||
glob->hasRowSecurity = false;
|
||||
|
||||
/*
|
||||
* Assess whether it's feasible to use parallel mode for this query.
|
||||
* We can't do this in a standalone backend, or if the command will
|
||||
* try to modify any data, or if this is a cursor operation, or if any
|
||||
* parallel-unsafe functions are present in the query tree.
|
||||
*
|
||||
* For now, we don't try to use parallel mode if we're running inside
|
||||
* a parallel worker. We might eventually be able to relax this
|
||||
* restriction, but for now it seems best not to have parallel workers
|
||||
* trying to create their own parallel workers.
|
||||
*/
|
||||
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 && !IsParallelWorker() &&
|
||||
!contain_parallel_unsafe((Node *) parse);
|
||||
|
||||
/*
|
||||
* glob->parallelModeOK should tell us whether it's necessary to impose
|
||||
* the parallel mode restrictions, but we don't actually want to impose
|
||||
* them unless we choose a parallel plan, so that people who mislabel
|
||||
* their functions but don't use parallelism anyway aren't harmed.
|
||||
* However, it's useful for testing purposes to be able to force the
|
||||
* restrictions to be imposed whenever a parallel plan is actually chosen
|
||||
* or not.
|
||||
*
|
||||
* (It's been suggested that we should always impose these restrictions
|
||||
* whenever glob->parallelModeOK is true, so that it's easier to notice
|
||||
* incorrectly-labeled functions sooner. That might be the right thing
|
||||
* to do, but for now I've taken this approach. We could also control
|
||||
* this with a GUC.)
|
||||
*
|
||||
* FIXME: It's assumed that code further down will set parallelModeNeeded
|
||||
* to true if a parallel path is actually chosen. Since the core
|
||||
* parallelism code isn't committed yet, this currently never happens.
|
||||
*/
|
||||
#ifdef FORCE_PARALLEL_MODE
|
||||
glob->parallelModeNeeded = glob->parallelModeOK;
|
||||
#else
|
||||
glob->parallelModeNeeded = false;
|
||||
#endif
|
||||
|
||||
/* Determine what fraction of the plan is likely to be scanned */
|
||||
if (cursorOptions & CURSOR_OPT_FAST_PLAN)
|
||||
{
|
||||
@ -293,6 +337,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
||||
result->invalItems = glob->invalItems;
|
||||
result->nParamExec = glob->nParamExec;
|
||||
result->hasRowSecurity = glob->hasRowSecurity;
|
||||
result->parallelModeNeeded = glob->parallelModeNeeded;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user