</listitem>
</varlistentry>
+ <varlistentry>
+ <term><literal>parallel_degree</> (<type>integer</>)</term>
+ <listitem>
+ <para>
+ 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
+ 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 <xref linkend="guc-max-parallel-degree">.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><literal>autovacuum_enabled</>, <literal>toast.autovacuum_enabled</literal> (<type>boolean</>)</term>
<listitem>
#include "commands/tablespace.h"
#include "commands/view.h"
#include "nodes/makefuncs.h"
+#include "postmaster/postmaster.h"
#include "utils/array.h"
#include "utils/attoptcache.h"
#include "utils/builtins.h"
0, 0, 0
#endif
},
+ {
+ {
+ "parallel_degree",
+ "Number of parallel processes that can be used per executor node for this relation.",
+ RELOPT_KIND_HEAP,
+ AccessExclusiveLock
+ },
+ -1, 0, MAX_BACKENDS
+ },
/* list terminator */
{{NULL}}
/*
- * Option parser for anything that uses StdRdOptions (i.e. fillfactor and
- * autovacuum)
+ * Option parser for anything that uses StdRdOptions.
*/
bytea *
default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
offsetof(StdRdOptions, autovacuum) +offsetof(AutoVacOpts, analyze_scale_factor)},
{"user_catalog_table", RELOPT_TYPE_BOOL,
- offsetof(StdRdOptions, user_catalog_table)}
+ offsetof(StdRdOptions, user_catalog_table)},
+ {"parallel_degree", RELOPT_TYPE_INT,
+ offsetof(StdRdOptions, parallel_degree)}
};
options = parseRelOptions(reloptions, validate, kind, &numoptions);
static void
create_parallel_paths(PlannerInfo *root, RelOptInfo *rel)
{
- int parallel_threshold = 1000;
- int parallel_degree = 1;
+ int parallel_degree = 1;
/*
- * If this relation is too small to be worth a parallel scan, just return
- * without doing anything ... unless it's an inheritance child. In that case,
- * we want to generate a parallel path here anyway. It might not be worthwhile
- * just for this relation, but when combined with all of its inheritance siblings
- * it may well pay off.
+ * If the user has set the parallel_degree reloption, we decide what to do
+ * based on the value of that option. Otherwise, we estimate a value.
*/
- if (rel->pages < parallel_threshold && rel->reloptkind == RELOPT_BASEREL)
- return;
+ 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 (rel->rel_parallel_degree == 0)
+ return;
- /*
- * Limit the degree of parallelism logarithmically based on the size of the
- * relation. This probably needs to be a good deal more sophisticated, but we
- * need something here for now.
- */
- while (rel->pages > parallel_threshold * 3 &&
- parallel_degree < max_parallel_degree)
+ /*
+ * Use the table parallel_degree, but don't go further than
+ * max_parallel_degree.
+ */
+ parallel_degree = Min(rel->rel_parallel_degree, max_parallel_degree);
+ }
+ else
{
- parallel_degree++;
- parallel_threshold *= 3;
- if (parallel_threshold >= PG_INT32_MAX / 3)
- break;
+ int parallel_threshold = 1000;
+
+ /*
+ * If this relation is too small to be worth a parallel scan, just
+ * return without doing anything ... unless it's an inheritance child.
+ * In that case, we want to generate a parallel path here anyway. It
+ * might not be worthwhile just for this relation, but when combined
+ * with all of its inheritance siblings it may well pay off.
+ */
+ if (rel->pages < parallel_threshold &&
+ rel->reloptkind == RELOPT_BASEREL)
+ return;
+
+ /*
+ * Limit the degree of parallelism logarithmically based on the size
+ * of the relation. This probably needs to be a good deal more
+ * sophisticated, but we need something here for now.
+ */
+ while (rel->pages > parallel_threshold * 3 &&
+ parallel_degree < max_parallel_degree)
+ {
+ parallel_degree++;
+ parallel_threshold *= 3;
+ if (parallel_threshold >= PG_INT32_MAX / 3)
+ break;
+ }
}
/* Add an unordered partial path based on a parallel sequential scan. */
estimate_rel_size(relation, rel->attr_widths - rel->min_attr,
&rel->pages, &rel->tuples, &rel->allvisfrac);
+ /* Retrive the parallel_degree reloption, if set. */
+ rel->rel_parallel_degree = RelationGetParallelDegree(relation, -1);
+
/*
* Make list of indexes. Ignore indexes on system catalogs if told to.
* Don't bother with indexes for an inheritance parent, either.
rel->consider_startup = (root->tuple_fraction > 0);
rel->consider_param_startup = false; /* might get changed later */
rel->consider_parallel = false; /* might get changed later */
+ rel->rel_parallel_degree = -1; /* set up in GetRelationInfo */
rel->reltarget = create_empty_pathtarget();
rel->pathlist = NIL;
rel->ppilist = NIL;
"autovacuum_vacuum_scale_factor",
"autovacuum_vacuum_threshold",
"fillfactor",
+ "parallel_degree",
"log_autovacuum_min_duration",
"toast.autovacuum_enabled",
"toast.autovacuum_freeze_max_age",
double allvisfrac;
PlannerInfo *subroot; /* if subquery */
List *subplan_params; /* if subquery */
+ int rel_parallel_degree; /* wanted number of parallel workers */
/* Information about foreign tables and foreign joins */
Oid serverid; /* identifies server for the table or join */
AutoVacOpts autovacuum; /* autovacuum-related options */
bool user_catalog_table; /* use as an additional catalog
* relation */
+ int parallel_degree; /* max number of parallel workers */
} StdRdOptions;
#define HEAP_MIN_FILLFACTOR 10
((relation)->rd_options ? \
((StdRdOptions *) (relation)->rd_options)->user_catalog_table : false)
+/*
+ * RelationGetParallelDegree
+ * Returns the relation's parallel_degree. Note multiple eval of argument!
+ */
+#define RelationGetParallelDegree(relation, defaultpd) \
+ ((relation)->rd_options ? \
+ ((StdRdOptions *) (relation)->rd_options)->parallel_degree : (defaultpd))
+
/*
* ViewOptions