]> granicus.if.org Git - postgresql/commitdiff
Add a 'parallel_degree' reloption.
authorRobert Haas <rhaas@postgresql.org>
Fri, 8 Apr 2016 15:14:56 +0000 (11:14 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 8 Apr 2016 15:14:56 +0000 (11:14 -0400)
The code that estimates what parallel degree should be uesd for the
scan of a relation is currently rather stupid, so add a parallel_degree
reloption that can be used to override the planner's rather limited
judgement.

Julien Rouhaud, reviewed by David Rowley, James Sewell, Amit Kapila,
and me.  Some further hacking by me.

doc/src/sgml/ref/create_table.sgml
src/backend/access/common/reloptions.c
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/relnode.c
src/bin/psql/tab-complete.c
src/include/nodes/relation.h
src/include/utils/rel.h

index cd234dbf4e3177e70e40de0242afede9b8d371ec..d1807ed0dbfe7b24b87721f270dd1a153691ce0b 100644 (file)
@@ -908,6 +908,19 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } | UNLOGGED ] TABLE [ IF NOT EXI
     </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>
index ea0755a8785d972a276c13bc6bbbb9fc2d9efca3..797be63c44b34d0a7f757c1c2ecdcd1772f57f5e 100644 (file)
@@ -26,6 +26,7 @@
 #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"
@@ -267,6 +268,15 @@ static relopt_int intRelOpts[] =
                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}}
@@ -1251,8 +1261,7 @@ fillRelOptions(void *rdopts, Size basesize,
 
 
 /*
- * 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)
@@ -1291,7 +1300,9 @@ 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);
index cc77ff9e1f04f31b4746707a8b1dfea6bc37f03f..17c1edd970360fc35a0b79bb827651cda6a611ba 100644 (file)
@@ -659,31 +659,55 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
 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. */
index 0f291275dcc08eb2358b3de91df8765f45906286..86cc640cf267c81f947fc9db4c0cc129e0a021c9 100644 (file)
@@ -133,6 +133,9 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
                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.
index 802eab3718ab06ea976b208365491a3695ea1407..187437b69416d9d427407e8760191132d0d67173 100644 (file)
@@ -107,6 +107,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
        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;
index cb8a06d15e44118a613c46c718b4b7a33e4cfd34..6d092711e838e397200873196beaf870962747cd 100644 (file)
@@ -1783,6 +1783,7 @@ psql_completion(const char *text, int start, int end)
                        "autovacuum_vacuum_scale_factor",
                        "autovacuum_vacuum_threshold",
                        "fillfactor",
+                       "parallel_degree",
                        "log_autovacuum_min_duration",
                        "toast.autovacuum_enabled",
                        "toast.autovacuum_freeze_max_age",
index d430f6e9fd4774787cfbb224c40c6e3a7475ac68..e9dfb663c203a5938d5de7d2f8e3fc86d78f2cc7 100644 (file)
@@ -522,6 +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 */
 
        /* Information about foreign tables and foreign joins */
        Oid                     serverid;               /* identifies server for the table or join */
index 51eb27a381bb16797b75c23871511753c4d9bb58..c7582c2a11ca27ab476a2f652e8a6bf3c8b366dc 100644 (file)
@@ -206,6 +206,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 */
 } StdRdOptions;
 
 #define HEAP_MIN_FILLFACTOR                    10
@@ -242,6 +243,14 @@ typedef struct StdRdOptions
        ((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