OSDN Git Service

Support parallel query
authorKyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Fri, 2 Sep 2016 07:55:14 +0000 (16:55 +0900)
committerKyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Mon, 5 Sep 2016 06:35:36 +0000 (15:35 +0900)
Support Gather node and related properties.

json2sql.pl
makeplanfile.sql
pgsp_json.c
pgsp_json_int.h
pgsp_json_text.c
pgsp_json_text.h

index b87ff36..5eba1f5 100755 (executable)
@@ -101,7 +101,8 @@ SELECT '### '||'xml-short        '||title||E'\n'||
 \echo  ###### text format output test
 SELECT '### '||'TEXT-short       '||title||E'\n'||
   pg_store_plans_textplan(splan)
-  FROM plans ORDER BY id;
+  FROM plans WHERE id >= 0 ORDER BY id;
+
 
 \echo  ###### long-json-as-a-source test
 SELECT '### '||'yaml-long JSON   '||title||E'\n'||
@@ -182,6 +183,7 @@ sub setplan0 {
   "Node Type": "SetOp",
   "Node Type": "LockRows",
   "Node Type": "Limit",
+  "Node Type": "Gather",
   "Parent Relationship": "Outer",
   "Parent Relationship": "Inner",
   "Parent Relationship": "Subquery",
@@ -221,6 +223,11 @@ sub setplan0 {
   "Group Key": "a",
   "Grouping Sets": "a",
   "Group Keys": "a",
+  "Parallel Aware": "true",
+  "Workers Planned": "0",
+  "Workers Launched": "0",
+  "Workers": "x",
+  "Worker Number": "0",
   "Filter": "a",
   "Join Filter": "a",
   "Hash Cond": "a",
index 4c85544..248719e 100644 (file)
@@ -182,4 +182,14 @@ explain (analyze on, buffers on, verbose on, format :format)
 explain (analyze on, buffers on, verbose on, format :format)
    SELECT * FROM tt1 TABLESAMPLE system(1) REPEATABLE (1);
 
+\echo ###### Parallel
+create table lt1 (a int, b text);
+alter table lt1 alter column b set storage plain;
+insert into lt1 (select a, repeat('x', 1000) from generate_series(0, 99999) a);
+set max_parallel_worders_per_gather to 2;
+set parallel_tuple_cost to 0;
+set parallel_setup_cost to 0;
+explain (analyze on, buffers on, verbose on, format :format)
+   SELECT * FROM lt1;
+
 -- BitmapAnd/Inner/Right/ForegnScan
index 61536d2..cd6660c 100644 (file)
@@ -97,6 +97,9 @@ word_table propfields[] =
        {P_GroupKey,            "-" ,"Group Key",                       NULL, true,  NULL,                              SETTER(group_key)},
        {P_GroupSets,           "=" ,"Grouping Sets",           NULL, true,  NULL,                              NULL},
        {P_GroupKeys,           "\\" ,"Group Keys",                     NULL, true,  NULL,                              SETTER(group_key)},
+       {P_Parallel,            "`" ,"Parallel Aware",          NULL, true,  NULL,                              SETTER(parallel_aware)},
+       {P_WorkersPlanned,      "{" ,"Workers Planned",         NULL, true,  NULL,                              SETTER(workers_planned)},
+       {P_WorkersLaunched, "}" ,"Workers Launched",    NULL, true,  NULL,                              SETTER(workers_launched)},
                                                                                                                  
        /* Values of these properties are ignored on normalization */
        {P_FunctionCall,        "y" ,"Function Call",           NULL, false, NULL,                              SETTER(func_call)},
@@ -145,6 +148,9 @@ word_table propfields[] =
        {P_SamplingMethod,  ""  ,"Sampling Method" ,    NULL, false,  NULL,                             SETTER(sampling_method)},
        {P_SamplingParams,  ""  ,"Sampling Parameters" , NULL, false,  NULL,                    SETTER(sampling_params)},
        {P_RepeatableSeed,  ""  ,"Repeatable Seed" ,    NULL, false,  NULL,                             SETTER(repeatable_seed)},
+       {P_Workers,             "[" ,"Workers",                         NULL, false,  NULL,                             NULL},
+       {P_WorkerNumber,    "]" ,"Worker Number",               NULL, false,  NULL,                             SETTER(worker_number)},
+
        {P_Invalid, NULL, NULL, NULL, false, NULL, NULL}
 };
 
@@ -184,6 +190,9 @@ word_table nodetypes[] =
        {T_SetOp,               "3" ,"SetOp",                   NULL, false, NULL, NULL},
        {T_LockRows,    "4" ,"LockRows",                NULL, false, NULL, NULL},
        {T_Limit,               "5" ,"Limit",                   NULL, false, NULL, NULL},
+#if PG_VERSION_NUM >= 90600
+       {T_Gather,              "6" ,"Gather",                  NULL, false, NULL, NULL},
+#endif
        {T_Invalid,             NULL, NULL, NULL, false, NULL, NULL}
 };
 
index e662a13..51a3699 100644 (file)
@@ -68,6 +68,8 @@ typedef enum
        P_TriggerName,
        P_TrgRelation,
        P_ConstraintName,
+       P_Parallel,
+       P_WorkersPlanned,
 
        P_FunctionCall,
        P_StartupCost,
@@ -114,7 +116,10 @@ typedef enum
        P_ConfTuples,
        P_SamplingMethod,
        P_SamplingParams,
-       P_RepeatableSeed
+       P_RepeatableSeed,
+       P_Workers,
+       P_WorkersLaunched,
+       P_WorkerNumber
 } pgsp_prop_tags;
 
 typedef struct
index bf3d809..1f3d58a 100644 (file)
@@ -94,6 +94,7 @@ CONVERSION_SETTER(setopcommand, conv_setsetopcommand);
 CONVERSION_SETTER(sort_method, conv_sortmethod);
 LIST_SETTER(sort_key);
 LIST_SETTER(group_key);
+BOOL_SETTER(parallel_aware);
 SQLQUOTE_SETTER(index_name);
 DEFAULT_SETTER(startup_cost);
 DEFAULT_SETTER(total_cost);
@@ -150,6 +151,9 @@ DEFAULT_SETTER(conflicting_tuples);
 DEFAULT_SETTER(sampling_method);
 LIST_SETTER(sampling_params);
 DEFAULT_SETTER(repeatable_seed);
+DEFAULT_SETTER(worker_number);
+DEFAULT_SETTER(workers_planned);
+DEFAULT_SETTER(workers_launched);
 
 #define ISZERO(s) (!s || strcmp(s, "0") == 0 || strcmp(s, "0.000") == 0 )
 #define HASSTRING(s) (s && strlen(s) > 0)
@@ -273,7 +277,13 @@ print_current_node(pgspParserContext *ctx)
        bool comma = false;
        int exind = 0;
 
-       if (v->node_type == T_Invalid)
+       /*
+        * The element objects in "Workers" list doesn't have node type, which
+        * would be named T_Worker if there were in node.h. So it needs a special
+        * treat.
+        */
+       
+       if (v->node_type == T_Invalid && !HASSTRING(v->worker_number))
                return;
 
        if (s->len > 0)
@@ -292,6 +302,9 @@ print_current_node(pgspParserContext *ctx)
        if (level > 1 && ctx->current_list == P_Invalid)
                appendStringInfoString(s, "->  ");
 
+       if (v->parallel_aware)
+               appendStringInfoString(s, "Parallel ");
+
        switch (v->nodetag)
        {
                case T_ModifyTable:
@@ -340,7 +353,21 @@ print_current_node(pgspParserContext *ctx)
                        break;
 
                default:
-                       appendStringInfoString(s, v->node_type);
+                       /* Existence of worker_number suggests this is a Worker node */
+                       if (HASSTRING(v->worker_number))
+                       {
+                               appendStringInfoString(s, "Worker");
+                               print_prop_if_exists(s, " ", v->worker_number, 0, 0);
+
+                               /* 
+                                * "Worker"s are individual JSON objects in a JSON list but
+                                * should be printed as just a property in text
+                                * representaion. Correct indent using exind here.
+                                */
+                               exind = -4;
+                       }
+                       else
+                               appendStringInfoString(s, v->node_type);
                        break;
        }
 
@@ -405,6 +432,8 @@ print_current_node(pgspParserContext *ctx)
        print_prop_if_exists(s, "Join Filter: " , v->join_filter, level, exind);
        print_prop_if_exists(s, "Index Cond: " , v->index_cond, level, exind);
        print_prop_if_exists(s, "Recheck Cond: ", v->recheck_cond, level, exind);
+       print_prop_if_exists(s, "Workers Planned: ", v->workers_planned, level, exind);
+       print_prop_if_exists(s, "Workers Launched: ", v->workers_launched, level, exind);
 
        if (HASSTRING(v->sampling_method))
        {
@@ -788,10 +817,11 @@ json_text_ofstart(void *state, char *fname, bool isnull)
        else
        {
                /*
-                * Print node immediately if the next level of Plan/Plans comes. The
-                * plan construct is tail-recursive so this doesn't harm.
+                * Print the current node immediately if the next level of
+                * Plan/Plans/Worers comes. This assumes that the plan output is
+                * strcutured tail-recursively.
                 */
-               if (p->tag == P_Plan || p->tag == P_Plans)
+               if (p->tag == P_Plan || p->tag == P_Plans || p->tag == P_Workers)
                {
                        print_current_node(ctx);
                        clear_nodeval(ctx->nodevals);
@@ -808,7 +838,8 @@ json_text_ofstart(void *state, char *fname, bool isnull)
                        v->tmp_schema_name = v->schema_name;
                        v->tmp_alias = v->alias;
                }
-               else if (p->tag == P_GroupSets)
+
+               if (p->tag == P_GroupSets || p->tag == P_Workers)
                {
                        ctx->current_list = p->tag;
                        ctx->list_fname = fname;
@@ -819,7 +850,7 @@ json_text_ofstart(void *state, char *fname, bool isnull)
                 * This paser prints partial result at the end of every P_Plan object,
                 * which includes elements in P_Plans list.
                 */
-               if (p->tag == P_Plan || p->tag == P_Plans)
+               if (p->tag == P_Plan || p->tag == P_Plans || p->tag == P_Workers)
                        ctx->plan_levels = bms_add_member(ctx->plan_levels, ctx->level);
                else
                        ctx->plan_levels = bms_del_member(ctx->plan_levels, ctx->level);
index 596778f..e756ebf 100644 (file)
@@ -92,6 +92,10 @@ typedef struct
        const char *sampling_method;
        StringInfo sampling_params;
        const char *repeatable_seed;
+       bool            parallel_aware;
+       const char *worker_number;
+       const char *workers_planned;
+       const char *workers_launched;
 
        const char *tmp_obj_name;
        const char *tmp_schema_name;
@@ -107,6 +111,9 @@ typedef struct
 #define SQLQUOTE_SETTER(name) \
        SETTERDECL(name) { vals->name = quote_identifier(val);}
 
+#define BOOL_SETTER(name) \
+       SETTERDECL(name) { vals->parallel_aware = (strcmp(val, "true") == 0 ? 1 : 0);}
+
 #define LIST_SETTER(name) \
        SETTERDECL(name) { \
                if (!vals->name || !vals->name->data[0])\
@@ -140,6 +147,7 @@ SETTERDECL(sort_method);
 SETTERDECL(sort_key);
 SETTERDECL(group_key);
 SETTERDECL(group_keys);
+SETTERDECL(parallel_aware);
 SETTERDECL(index_name);
 SETTERDECL(startup_cost);
 SETTERDECL(total_cost);
@@ -197,3 +205,6 @@ SETTERDECL(conflicting_tuples);
 SETTERDECL(sampling_method);
 SETTERDECL(sampling_params);
 SETTERDECL(repeatable_seed);
+SETTERDECL(worker_number);
+SETTERDECL(workers_planned);
+SETTERDECL(workers_launched);