Commit 26acb54a authored by Amit Kapila's avatar Amit Kapila

Revert "Enable parallel SELECT for "INSERT INTO ... SELECT ..."."

To allow inserts in parallel-mode this feature has to ensure that all the
constraints, triggers, etc. are parallel-safe for the partition hierarchy
which is costly and we need to find a better way to do that. Additionally,
we could have used existing cached information in some cases like indexes,
domains, etc. to determine the parallel-safety.

List of commits reverted, in reverse chronological order:

ed62d373 Doc: Update description for parallel insert reloption.
c8f78b61 Add a new GUC and a reloption to enable inserts in parallel-mode.
c5be48f0 Improve FK trigger parallel-safety check added by 05c8482f.
e2cda3c2 Fix use of relcache TriggerDesc field introduced by commit 05c8482f.
e4e87a32 Fix valgrind issue in commit 05c8482f.
05c8482f Enable parallel SELECT for "INSERT INTO ... SELECT ...".

Discussion: https://postgr.es/m/E1lMiB9-0001c3-SY@gemulon.postgresql.org
parent 84007043
......@@ -5072,29 +5072,6 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
</listitem>
</varlistentry>
<varlistentry id="guc-enable-parallel-insert" xreflabel="enable_parallel_insert">
<term><varname>enable_parallel_insert</varname> (<type>boolean</type>)
<indexterm>
<primary><varname>enable_parallel_insert</varname> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Enables or disables the query planner's use of parallel plans for
<command>INSERT</command> commands. The default is <literal>on</literal>.
When enabled, the planner performs additional parallel-safety checks
on the target table's attributes and indexes, in order to determine
if it's safe to use a parallel plan for <command>INSERT</command>. In
cases such as when the target table has a large number of partitions,
and particularly also when that table uses something parallel-unsafe
that prevents parallelism, the overhead of these checks may become
prohibitively high. To address this potential overhead in these cases,
this option can be used to disable the use of parallel plans for
<command>INSERT</command>.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2 id="runtime-config-query-constants">
......
......@@ -155,9 +155,6 @@ EXPLAIN SELECT * FROM pgbench_accounts WHERE filler LIKE '%x%';
<listitem>
<para><command>SELECT INTO</command></para>
</listitem>
<listitem>
<para><command>INSERT INTO ... SELECT</command></para>
</listitem>
<listitem>
<para><command>CREATE MATERIALIZED VIEW</command></para>
</listitem>
......
......@@ -738,8 +738,7 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
<para>
<literal>SHARE UPDATE EXCLUSIVE</literal> lock will be taken for
fillfactor, toast and autovacuum storage parameters, as well as the
planner parameters <varname>parallel_workers</varname> and
<varname>parallel_insert_enabled</varname>.
planner parameter <varname>parallel_workers</varname>.
</para>
</listitem>
</varlistentry>
......
......@@ -1369,9 +1369,8 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
If a table parameter value is set and the
equivalent <literal>toast.</literal> parameter is not, the TOAST table
will use the table's parameter value.
These parameters, with the exception of
<literal>parallel_insert_enabled</literal>, are not supported on partitioned
tables, but may be specified for individual leaf partitions.
Specifying these parameters for partitioned tables is not supported,
but you may specify them for individual leaf partitions.
</para>
<variablelist>
......@@ -1441,32 +1440,6 @@ WITH ( MODULUS <replaceable class="parameter">numeric_literal</replaceable>, REM
</listitem>
</varlistentry>
<varlistentry id="reloption-parallel-insert-enabled" xreflabel="parallel_insert_enabled">
<term><literal>parallel_insert_enabled</literal> (<type>boolean</type>)
<indexterm>
<primary><varname>parallel_insert_enabled</varname> storage parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Enables or disables the query planner's use of parallel insert for
this table. When enabled (and provided that
<xref linkend="guc-enable-parallel-insert"/> is also <literal>true</literal>),
the planner performs additional parallel-safety checks on the table's
attributes and indexes, in order to determine if it's safe to use a
parallel plan for <command>INSERT</command>. The default is
<literal>true</literal>. In cases such as when the table has a large
number of partitions, and particularly also when that table uses a
parallel-unsafe feature that prevents parallelism, the overhead of these
checks may become prohibitively high. To address this potential overhead
in these cases, this option can be used to disable the use of parallel
insert for this table. Note that if the target table of the parallel
insert is partitioned, the <literal>parallel_insert_enabled</literal>
option values of the partitions are ignored.
</para>
</listitem>
</varlistentry>
<varlistentry id="reloption-autovacuum-enabled" xreflabel="autovacuum_enabled">
<term><literal>autovacuum_enabled</literal>, <literal>toast.autovacuum_enabled</literal> (<type>boolean</type>)
<indexterm>
......
......@@ -168,15 +168,6 @@ static relopt_bool boolRelOpts[] =
},
true
},
{
{
"parallel_insert_enabled",
"Enables \"parallel insert\" feature for this table",
RELOPT_KIND_HEAP | RELOPT_KIND_PARTITIONED,
ShareUpdateExclusiveLock
},
true
},
/* list terminator */
{{NULL}}
};
......@@ -1868,9 +1859,7 @@ default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"vacuum_index_cleanup", RELOPT_TYPE_BOOL,
offsetof(StdRdOptions, vacuum_index_cleanup)},
{"vacuum_truncate", RELOPT_TYPE_BOOL,
offsetof(StdRdOptions, vacuum_truncate)},
{"parallel_insert_enabled", RELOPT_TYPE_BOOL,
offsetof(StdRdOptions, parallel_insert_enabled)}
offsetof(StdRdOptions, vacuum_truncate)}
};
return (bytea *) build_reloptions(reloptions, validate, kind,
......@@ -1972,15 +1961,13 @@ build_local_reloptions(local_relopts *relopts, Datum options, bool validate)
bytea *
partitioned_table_reloptions(Datum reloptions, bool validate)
{
static const relopt_parse_elt tab[] = {
{"parallel_insert_enabled", RELOPT_TYPE_BOOL,
offsetof(PartitionedTableRdOptions, parallel_insert_enabled)}
};
/*
* There are no options for partitioned tables yet, but this is able to do
* some validation.
*/
return (bytea *) build_reloptions(reloptions, validate,
RELOPT_KIND_PARTITIONED,
sizeof(PartitionedTableRdOptions),
tab, lengthof(tab));
0, NULL, 0);
}
/*
......
......@@ -1014,32 +1014,6 @@ IsInParallelMode(void)
return CurrentTransactionState->parallelModeLevel != 0;
}
/*
* PrepareParallelModePlanExec
*
* Prepare for entering parallel mode plan execution, based on command-type.
*/
void
PrepareParallelModePlanExec(CmdType commandType)
{
if (IsModifySupportedInParallelMode(commandType))
{
Assert(!IsInParallelMode());
/*
* Prepare for entering parallel mode by assigning a TransactionId.
* Failure to do this now would result in heap_insert() subsequently
* attempting to assign a TransactionId whilst in parallel-mode, which
* is not allowed.
*
* This approach has a disadvantage in that if the underlying SELECT
* does not return any rows, then the TransactionId is not used,
* however that shouldn't happen in practice in many cases.
*/
(void) GetCurrentTransactionId();
}
}
/*
* CommandCounterIncrement
*/
......
......@@ -1512,10 +1512,7 @@ ExecutePlan(EState *estate,
estate->es_use_parallel_mode = use_parallel_mode;
if (use_parallel_mode)
{
PrepareParallelModePlanExec(estate->es_plannedstmt->commandType);
EnterParallelMode();
}
/*
* Loop until we've processed the proper number of tuples from the plan.
......
......@@ -96,7 +96,6 @@ _copyPlannedStmt(const PlannedStmt *from)
COPY_BITMAPSET_FIELD(rewindPlanIDs);
COPY_NODE_FIELD(rowMarks);
COPY_NODE_FIELD(relationOids);
COPY_NODE_FIELD(partitionOids);
COPY_NODE_FIELD(invalItems);
COPY_NODE_FIELD(paramExecTypes);
COPY_NODE_FIELD(utilityStmt);
......
......@@ -314,7 +314,6 @@ _outPlannedStmt(StringInfo str, const PlannedStmt *node)
WRITE_BITMAPSET_FIELD(rewindPlanIDs);
WRITE_NODE_FIELD(rowMarks);
WRITE_NODE_FIELD(relationOids);
WRITE_NODE_FIELD(partitionOids);
WRITE_NODE_FIELD(invalItems);
WRITE_NODE_FIELD(paramExecTypes);
WRITE_NODE_FIELD(utilityStmt);
......@@ -2222,7 +2221,6 @@ _outPlannerGlobal(StringInfo str, const PlannerGlobal *node)
WRITE_NODE_FIELD(resultRelations);
WRITE_NODE_FIELD(appendRelations);
WRITE_NODE_FIELD(relationOids);
WRITE_NODE_FIELD(partitionOids);
WRITE_NODE_FIELD(invalItems);
WRITE_NODE_FIELD(paramExecTypes);
WRITE_UINT_FIELD(lastPHId);
......
......@@ -1591,7 +1591,6 @@ _readPlannedStmt(void)
READ_BITMAPSET_FIELD(rewindPlanIDs);
READ_NODE_FIELD(rowMarks);
READ_NODE_FIELD(relationOids);
READ_NODE_FIELD(partitionOids);
READ_NODE_FIELD(invalItems);
READ_NODE_FIELD(paramExecTypes);
READ_NODE_FIELD(utilityStmt);
......
......@@ -129,8 +129,6 @@ Cost disable_cost = 1.0e10;
int max_parallel_workers_per_gather = 2;
bool enable_parallel_insert = true;
bool enable_seqscan = true;
bool enable_indexscan = true;
bool enable_indexonlyscan = true;
......
......@@ -305,7 +305,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
glob->resultRelations = NIL;
glob->appendRelations = NIL;
glob->relationOids = NIL;
glob->partitionOids = NIL;
glob->invalItems = NIL;
glob->paramExecTypes = NIL;
glob->lastPHId = 0;
......@@ -317,16 +316,16 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
/*
* 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 (except for Insert), or if this is a cursor operation,
* or if GUCs are set to values that don't permit parallelism, or if
* parallel-unsafe functions are present in the query tree.
* modify any data, or if this is a cursor operation, or if GUCs are set
* to values that don't permit parallelism, or if parallel-unsafe
* functions are present in the query tree.
*
* (Note that we do allow CREATE TABLE AS, INSERT INTO...SELECT, SELECT
* INTO, and CREATE MATERIALIZED VIEW to use parallel plans. However, as
* of now, only the leader backend writes into a completely new table. In
* the future, we can extend it to allow workers to write into the table.
* However, to allow parallel updates and deletes, we have to solve other
* problems, especially around combo CIDs.)
* (Note that we do allow CREATE TABLE AS, SELECT INTO, and CREATE
* MATERIALIZED VIEW to use parallel plans, but as of now, only the leader
* backend writes into a completely new table. In the future, we can
* extend it to allow workers to write into the table. However, to allow
* parallel updates and deletes, we have to solve other problems,
* especially around combo CIDs.)
*
* 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
......@@ -335,14 +334,13 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
*/
if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
IsUnderPostmaster &&
(parse->commandType == CMD_SELECT ||
is_parallel_allowed_for_modify(parse)) &&
parse->commandType == CMD_SELECT &&
!parse->hasModifyingCTE &&
max_parallel_workers_per_gather > 0 &&
!IsParallelWorker())
{
/* all the cheap tests pass, so scan the query tree */
glob->maxParallelHazard = max_parallel_hazard(parse, glob);
glob->maxParallelHazard = max_parallel_hazard(parse);
glob->parallelModeOK = (glob->maxParallelHazard != PROPARALLEL_UNSAFE);
}
else
......@@ -523,19 +521,6 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
result->rewindPlanIDs = glob->rewindPlanIDs;
result->rowMarks = glob->finalrowmarks;
result->relationOids = glob->relationOids;
/*
* Register the Oids of parallel-safety-checked partitions as plan
* dependencies. This is only really needed in the case of a parallel plan
* so that if parallel-unsafe properties are subsequently defined on the
* partitions, the cached parallel plan will be invalidated, and a
* non-parallel plan will be generated.
*
* We also use this list to acquire locks on partitions before executing
* cached plan. See AcquireExecutorLocks().
*/
if (glob->partitionOids != NIL && glob->parallelModeNeeded)
result->partitionOids = glob->partitionOids;
result->invalItems = glob->invalItems;
result->paramExecTypes = glob->paramExecTypes;
/* utilityStmt should be null, but we might as well copy it */
......
This diff is collapsed.
......@@ -1735,23 +1735,6 @@ QueryListGetPrimaryStmt(List *stmts)
return NULL;
}
static void
AcquireExecutorLocksOnPartitions(List *partitionOids, int lockmode,
bool acquire)
{
ListCell *lc;
foreach(lc, partitionOids)
{
Oid partOid = lfirst_oid(lc);
if (acquire)
LockRelationOid(partOid, lockmode);
else
UnlockRelationOid(partOid, lockmode);
}
}
/*
* AcquireExecutorLocks: acquire locks needed for execution of a cached plan;
* or release them if acquire is false.
......@@ -1765,8 +1748,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
{
PlannedStmt *plannedstmt = lfirst_node(PlannedStmt, lc1);
ListCell *lc2;
Index rti,
resultRelation = 0;
if (plannedstmt->commandType == CMD_UTILITY)
{
......@@ -1784,9 +1765,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
continue;
}
rti = 1;
if (plannedstmt->resultRelations)
resultRelation = linitial_int(plannedstmt->resultRelations);
foreach(lc2, plannedstmt->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc2);
......@@ -1804,14 +1782,6 @@ AcquireExecutorLocks(List *stmt_list, bool acquire)
LockRelationOid(rte->relid, rte->rellockmode);
else
UnlockRelationOid(rte->relid, rte->rellockmode);
/* Lock partitions ahead of modifying them in parallel mode. */
if (rti == resultRelation &&
plannedstmt->partitionOids != NIL)
AcquireExecutorLocksOnPartitions(plannedstmt->partitionOids,
rte->rellockmode, acquire);
rti++;
}
}
}
......@@ -2020,8 +1990,7 @@ PlanCacheRelCallback(Datum arg, Oid relid)
if (plannedstmt->commandType == CMD_UTILITY)
continue; /* Ignore utility statements */
if ((relid == InvalidOid) ? plannedstmt->relationOids != NIL :
(list_member_oid(plannedstmt->relationOids, relid) ||
list_member_oid(plannedstmt->partitionOids, relid)))
list_member_oid(plannedstmt->relationOids, relid))
{
/* Invalidate the generic plan only */
plansource->gplan->is_valid = false;
......
......@@ -1131,16 +1131,6 @@ static struct config_bool ConfigureNamesBool[] =
true,
NULL, NULL, NULL
},
{
{"enable_parallel_insert", PGC_USERSET, QUERY_TUNING_METHOD,
gettext_noop("Enables the planner's use of parallel plans for INSERT commands."),
NULL,
GUC_EXPLAIN
},
&enable_parallel_insert,
true,
NULL, NULL, NULL
},
{
/* Not for general use --- used by SET SESSION AUTHORIZATION */
{"is_superuser", PGC_INTERNAL, UNGROUPED,
......
......@@ -371,7 +371,6 @@
#enable_partitionwise_aggregate = off
#enable_parallel_hash = on
#enable_partition_pruning = on
#enable_parallel_insert = on
# - Planner Cost Constants -
......
......@@ -1118,7 +1118,6 @@ static const char *const table_storage_parameters[] = {
"autovacuum_vacuum_threshold",
"fillfactor",
"log_autovacuum_min_duration",
"parallel_insert_enabled",
"parallel_workers",
"toast.autovacuum_enabled",
"toast.autovacuum_freeze_max_age",
......
......@@ -466,20 +466,5 @@ extern void ParsePrepareRecord(uint8 info, xl_xact_prepare *xlrec, xl_xact_parse
extern void EnterParallelMode(void);
extern void ExitParallelMode(void);
extern bool IsInParallelMode(void);
extern void PrepareParallelModePlanExec(CmdType commandType);
/*
* IsModifySupportedInParallelMode
*
* Indicates whether execution of the specified table-modification command
* (INSERT/UPDATE/DELETE) in parallel-mode is supported, subject to certain
* parallel-safety conditions.
*/
static inline bool
IsModifySupportedInParallelMode(CmdType commandType)
{
/* Currently only INSERT is supported */
return (commandType == CMD_INSERT);
}
#endif /* XACT_H */
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202103232
#define CATALOG_VERSION_NO 202103241
#endif
......@@ -3748,11 +3748,11 @@
# Generic referential integrity constraint triggers
{ oid => '1644', descr => 'referential integrity FOREIGN KEY ... REFERENCES',
proname => 'RI_FKey_check_ins', provolatile => 'v', proparallel => 'r',
prorettype => 'trigger', proargtypes => '', prosrc => 'RI_FKey_check_ins' },
proname => 'RI_FKey_check_ins', provolatile => 'v', prorettype => 'trigger',
proargtypes => '', prosrc => 'RI_FKey_check_ins' },
{ oid => '1645', descr => 'referential integrity FOREIGN KEY ... REFERENCES',
proname => 'RI_FKey_check_upd', provolatile => 'v', proparallel => 'r',
prorettype => 'trigger', proargtypes => '', prosrc => 'RI_FKey_check_upd' },
proname => 'RI_FKey_check_upd', provolatile => 'v', prorettype => 'trigger',
proargtypes => '', prosrc => 'RI_FKey_check_upd' },
{ oid => '1646', descr => 'referential integrity ON DELETE CASCADE',
proname => 'RI_FKey_cascade_del', provolatile => 'v', prorettype => 'trigger',
proargtypes => '', prosrc => 'RI_FKey_cascade_del' },
......
......@@ -120,8 +120,6 @@ typedef struct PlannerGlobal
List *relationOids; /* OIDs of relations the plan depends on */
List *partitionOids; /* OIDs of partitions the plan depends on */
List *invalItems; /* other dependencies, as PlanInvalItems */
List *paramExecTypes; /* type OIDs for PARAM_EXEC Params */
......
......@@ -79,8 +79,6 @@ typedef struct PlannedStmt
List *relationOids; /* OIDs of relations the plan depends on */
List *partitionOids; /* OIDs of partitions the plan depends on */
List *invalItems; /* other dependencies, as PlanInvalItems */
List *paramExecTypes; /* type OIDs for PARAM_EXEC Params */
......
......@@ -32,7 +32,7 @@ extern double expression_returns_set_rows(PlannerInfo *root, Node *clause);
extern bool contain_subplans(Node *clause);
extern char max_parallel_hazard(Query *parse, PlannerGlobal *glob);
extern char max_parallel_hazard(Query *parse);
extern bool is_parallel_safe(PlannerInfo *root, Node *node);
extern bool contain_nonstrict_functions(Node *clause);
extern bool contain_exec_param(Node *clause, List *param_ids);
......@@ -52,6 +52,5 @@ extern void CommuteOpExpr(OpExpr *clause);
extern Query *inline_set_returning_function(PlannerInfo *root,
RangeTblEntry *rte);
extern bool is_parallel_allowed_for_modify(Query *parse);
#endif /* CLAUSES_H */
......@@ -47,7 +47,6 @@ typedef enum
/* parameter variables and flags (see also optimizer.h) */
extern PGDLLIMPORT Cost disable_cost;
extern PGDLLIMPORT int max_parallel_workers_per_gather;
extern PGDLLIMPORT bool enable_parallel_insert;
extern PGDLLIMPORT bool enable_seqscan;
extern PGDLLIMPORT bool enable_indexscan;
extern PGDLLIMPORT bool enable_indexonlyscan;
......
......@@ -306,8 +306,6 @@ typedef struct StdRdOptions
int parallel_workers; /* max number of parallel workers */
bool vacuum_index_cleanup; /* enables index vacuuming and cleanup */
bool vacuum_truncate; /* enables vacuum to truncate a relation */
bool parallel_insert_enabled; /* enables planner's use of
* parallel insert */
} StdRdOptions;
#define HEAP_MIN_FILLFACTOR 10
......@@ -425,29 +423,6 @@ typedef struct ViewOptions
((ViewOptions *) (relation)->rd_options)->check_option == \
VIEW_OPTION_CHECK_OPTION_CASCADED)
/*
* PartitionedTableRdOptions
* Contents of rd_options for partitioned tables
*/
typedef struct PartitionedTableRdOptions
{
int32 vl_len_; /* varlena header (do not touch directly!) */
bool parallel_insert_enabled; /* enables planner's use of
* parallel insert */
} PartitionedTableRdOptions;
/*
* RelationGetParallelInsert
* Returns the relation's parallel_insert_enabled reloption setting.
* Note multiple eval of argument!
*/
#define RelationGetParallelInsert(relation, defaultpd) \
((relation)->rd_options ? \
(relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ? \
((PartitionedTableRdOptions *) (relation)->rd_options)->parallel_insert_enabled : \
((StdRdOptions *) (relation)->rd_options)->parallel_insert_enabled) : \
(defaultpd))
/*
* RelationIsValid
* True iff relation descriptor is valid.
......
This diff is collapsed.
......@@ -107,14 +107,13 @@ select name, setting from pg_settings where name like 'enable%';
enable_nestloop | on
enable_parallel_append | on
enable_parallel_hash | on
enable_parallel_insert | on
enable_partition_pruning | on
enable_partitionwise_aggregate | off
enable_partitionwise_join | off
enable_seqscan | on
enable_sort | on
enable_tidscan | on
(19 rows)
(18 rows)
-- Test that the pg_timezone_names and pg_timezone_abbrevs views are
-- more-or-less working. We can't test their contents in any great detail
......
......@@ -90,7 +90,6 @@ test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8
# run by itself so it can run parallel workers
test: select_parallel
test: write_parallel
test: insert_parallel
# no relation related tests can be put in this group
test: publication subscription
......
......@@ -148,7 +148,6 @@ test: stats_ext
test: collate.linux.utf8
test: select_parallel
test: write_parallel
test: insert_parallel
test: publication
test: subscription
test: select_views
......
This diff is collapsed.
......@@ -1797,7 +1797,6 @@ PartitionSpec
PartitionTupleRouting
PartitionedRelPruneInfo
PartitionedRelPruningData
PartitionedTableRdOptions
PartitionwiseAggregateType
PasswordType
Path
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment