OSDN Git Service

Refactor hint application mechamism next step
authorKyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Fri, 10 Feb 2017 08:19:43 +0000 (17:19 +0900)
committerKyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Fri, 10 Feb 2017 08:19:43 +0000 (17:19 +0900)
I removed useless code forgotten to be removed in
add_paths_to_joinrel_wrapper by the previous refactoring. Addition to
that, find_scan_method_hint and find_parallel_hint are found not to
require the third parameter rel, so removed it. Some inadequate tests
are fixed and changed according to change of unclear behaviors.

expected/ut-S.out
expected/ut-W.out
pg_hint_plan.c
sql/ut-W.sql

index 06fc573..5b9260d 100644 (file)
@@ -5227,18 +5227,18 @@ error hint:
 EXPLAIN (COSTS false) SELECT * FROM s1.p2 WHERE c1 = 1;
 LOG:  pg_hint_plan:
 used hint:
-not used hint:
 IndexScan(p2c1)
+not used hint:
 duplication hint:
 error hint:
 
-        QUERY PLAN        
---------------------------
+              QUERY PLAN               
+---------------------------------------
  Append
    ->  Seq Scan on p2
          Filter: (c1 = 1)
-   ->  Seq Scan on p2c1
-         Filter: (c1 = 1)
+   ->  Index Scan using p2c1_i on p2c1
+         Index Cond: (c1 = 1)
    ->  Seq Scan on p2c1c1
          Filter: (c1 = 1)
 (7 rows)
index 93d1f1a..e7496a5 100644 (file)
@@ -5,7 +5,7 @@ SET pg_hint_plan.debug_print TO on;
 SET client_min_messages TO LOG;
 CREATE TABLE s1.tl (a int);
 INSERT INTO s1.tl (SELECT a FROM generate_series(0, 100000) a);
--- Queries on ordinary tables
+-- Queries on ordinary tables with default setting
 EXPLAIN (COSTS false) SELECT * FROM s1.t1;
    QUERY PLAN   
 ----------------
@@ -15,6 +15,7 @@ EXPLAIN (COSTS false) SELECT * FROM s1.t1;
 SET parallel_setup_cost to 0;
 SET parallel_tuple_cost to 0;
 SET min_parallel_relation_size to 0;
+SET max_parallel_workers_per_gather to DEFAULT;
 /*+Parallel(t1 10)*/
 EXPLAIN (COSTS false) SELECT * FROM s1.t1;
 LOG:  pg_hint_plan:
@@ -47,9 +48,6 @@ error hint:
    ->  Parallel Seq Scan on t1
 (3 rows)
 
-SET parallel_setup_cost to DEFAULT;
-SET parallel_tuple_cost to DEFAULT;
-SET min_parallel_relation_size to DEFAULT;
 /*+Parallel(t1 10 hard)*/
 EXPLAIN (COSTS false) SELECT * FROM s1.t1;
 LOG:  pg_hint_plan:
@@ -123,20 +121,20 @@ error hint:
          ->  Parallel Seq Scan on p1_c3_c2
 (12 rows)
 
--- hinting on children don't work but enables parallel
+-- hinting on children makes the whole inheritance parallel
 /*+Parallel(p1_c1 10 hard)*/
 EXPLAIN (COSTS false) SELECT * FROM p1;
 LOG:  pg_hint_plan:
 used hint:
-not used hint:
 Parallel(p1_c1 10 hard)
+not used hint:
 duplication hint:
 error hint:
 
                 QUERY PLAN                 
 -------------------------------------------
  Gather
-   Workers Planned: 1
+   Workers Planned: 10
    ->  Append
          ->  Parallel Seq Scan on p1
          ->  Parallel Seq Scan on p1_c1
@@ -150,106 +148,103 @@ error hint:
 (12 rows)
 
 -- Joins
-EXPLAIN (COSTS false) SELECT * FROM p1_c1 join p2_c1 on p1_c1.id = p2_c1.id;
-               QUERY PLAN               
-----------------------------------------
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
+                QUERY PLAN                
+------------------------------------------
  Hash Join
-   Hash Cond: (p1_c1.id = p2_c1.id)
-   ->  Append
-         ->  Seq Scan on p1_c1
-         ->  Seq Scan on p1_c1_c1
-         ->  Seq Scan on p1_c1_c2
+   Hash Cond: (p1_c1_c1.id = p2_c1_c1.id)
+   ->  Seq Scan on p1_c1_c1
    ->  Hash
-         ->  Append
-               ->  Seq Scan on p2_c1
-               ->  Seq Scan on p2_c1_c1
-               ->  Seq Scan on p2_c1_c2
-(11 rows)
+         ->  Seq Scan on p2_c1_c1
+(5 rows)
 
-/*+Parallel(p1_c1 10 hard)*/
-EXPLAIN (COSTS false) SELECT * FROM p1_c1 join p2_c1 on p1_c1.id = p2_c1.id;
+/*+Parallel(p1_c1_c1 10 hard)*/
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
 LOG:  pg_hint_plan:
 used hint:
-Parallel(p1_c1 10 hard)
+Parallel(p1_c1_c1 10 hard)
 not used hint:
 duplication hint:
 error hint:
 
-                      QUERY PLAN                       
--------------------------------------------------------
+                   QUERY PLAN                    
+-------------------------------------------------
  Hash Join
-   Hash Cond: (p1_c1.id = p2_c1.id)
-   ->  Gather
-         Workers Planned: 10
-         ->  Append
-               ->  Parallel Seq Scan on p1_c1
-               ->  Parallel Seq Scan on p1_c1_c1
-               ->  Parallel Seq Scan on p1_c1_c2
+   Hash Cond: (p2_c1_c1.id = p1_c1_c1.id)
+   ->  Seq Scan on p2_c1_c1
    ->  Hash
          ->  Gather
-               Workers Planned: 1
-               ->  Append
-                     ->  Parallel Seq Scan on p2_c1
-                     ->  Parallel Seq Scan on p2_c1_c1
-                     ->  Parallel Seq Scan on p2_c1_c2
-(15 rows)
+               Workers Planned: 10
+               ->  Parallel Seq Scan on p1_c1_c1
+(7 rows)
 
-/*+Parallel(p2_c1 10 hard)*/
-EXPLAIN (COSTS false) SELECT * FROM p1_c1 join p2_c1 on p1_c1.id = p2_c1.id;
+SET parallel_setup_cost to 0;
+SET parallel_tuple_cost to 0;
+SET min_parallel_relation_size to 0;
+/*+Parallel(p1_c1_c1 10 soft) Parallel(p2_c1_c1 0)*/
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
 LOG:  pg_hint_plan:
 used hint:
-Parallel(p2_c1 10 hard)
+Parallel(p1_c1_c1 10 soft)
+Parallel(p2_c1_c1 0 soft)
 not used hint:
 duplication hint:
 error hint:
 
-                      QUERY PLAN                       
--------------------------------------------------------
- Hash Join
-   Hash Cond: (p1_c1.id = p2_c1.id)
-   ->  Gather
-         Workers Planned: 1
-         ->  Append
-               ->  Parallel Seq Scan on p1_c1
-               ->  Parallel Seq Scan on p1_c1_c1
-               ->  Parallel Seq Scan on p1_c1_c2
-   ->  Hash
-         ->  Gather
-               Workers Planned: 10
-               ->  Append
-                     ->  Parallel Seq Scan on p2_c1
-                     ->  Parallel Seq Scan on p2_c1_c1
-                     ->  Parallel Seq Scan on p2_c1_c2
-(15 rows)
+                   QUERY PLAN                   
+------------------------------------------------
+ Gather
+   Workers Planned: 1
+   ->  Hash Join
+         Hash Cond: (p1_c1_c1.id = p2_c1_c1.id)
+         ->  Parallel Seq Scan on p1_c1_c1
+         ->  Hash
+               ->  Seq Scan on p2_c1_c1
+(7 rows)
 
-/*+Parallel(p1_c1 10 hard) Parallel(p2_c1 10 hard)*/
-EXPLAIN (COSTS false) SELECT * FROM p1_c1 join p2_c1 on p1_c1.id = p2_c1.id;
+/*+Parallel(p1_c1_c1 10 hard) Parallel(p2_c1_c1 0)*/
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
 LOG:  pg_hint_plan:
 used hint:
-Parallel(p1_c1 10 hard)
-Parallel(p2_c1 10 hard)
+Parallel(p1_c1_c1 10 hard)
+Parallel(p2_c1_c1 0 soft)
 not used hint:
 duplication hint:
 error hint:
 
-                      QUERY PLAN                       
--------------------------------------------------------
+                   QUERY PLAN                   
+------------------------------------------------
+ Gather
+   Workers Planned: 10
+   ->  Hash Join
+         Hash Cond: (p1_c1_c1.id = p2_c1_c1.id)
+         ->  Parallel Seq Scan on p1_c1_c1
+         ->  Hash
+               ->  Seq Scan on p2_c1_c1
+(7 rows)
+
+/*+Parallel(p1_c1_c1 10 hard) Parallel(p2_c1_c1 10 hard)*/
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
+LOG:  pg_hint_plan:
+used hint:
+Parallel(p1_c1_c1 10 hard)
+Parallel(p2_c1_c1 10 hard)
+not used hint:
+duplication hint:
+error hint:
+
+                   QUERY PLAN                    
+-------------------------------------------------
  Hash Join
-   Hash Cond: (p1_c1.id = p2_c1.id)
+   Hash Cond: (p1_c1_c1.id = p2_c1_c1.id)
    ->  Gather
          Workers Planned: 10
-         ->  Append
-               ->  Parallel Seq Scan on p1_c1
-               ->  Parallel Seq Scan on p1_c1_c1
-               ->  Parallel Seq Scan on p1_c1_c2
+         ->  Parallel Seq Scan on p1_c1_c1
    ->  Hash
          ->  Gather
                Workers Planned: 10
-               ->  Append
-                     ->  Parallel Seq Scan on p2_c1
-                     ->  Parallel Seq Scan on p2_c1_c1
-                     ->  Parallel Seq Scan on p2_c1_c2
-(15 rows)
+               ->  Parallel Seq Scan on p2_c1_c1
+(9 rows)
 
 -- Joins on inheritance tables
 SET parallel_setup_cost to 0;
@@ -295,6 +290,45 @@ error hint:
                      ->  Parallel Seq Scan on p2_c3_c2
 (27 rows)
 
+/*+Parallel(p1 10)Parallel(p2 0)*/
+EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
+LOG:  pg_hint_plan:
+used hint:
+Parallel(p1 10 soft)
+Parallel(p2 0 soft)
+not used hint:
+duplication hint:
+error hint:
+
+                   QUERY PLAN                    
+-------------------------------------------------
+ Gather
+   Workers Planned: 1
+   ->  Hash Join
+         Hash Cond: (p1.id = p2.id)
+         ->  Append
+               ->  Parallel Seq Scan on p1
+               ->  Parallel Seq Scan on p1_c1
+               ->  Parallel Seq Scan on p1_c2
+               ->  Parallel Seq Scan on p1_c3
+               ->  Parallel Seq Scan on p1_c4
+               ->  Parallel Seq Scan on p1_c1_c1
+               ->  Parallel Seq Scan on p1_c1_c2
+               ->  Parallel Seq Scan on p1_c3_c1
+               ->  Parallel Seq Scan on p1_c3_c2
+         ->  Hash
+               ->  Append
+                     ->  Seq Scan on p2
+                     ->  Seq Scan on p2_c1
+                     ->  Seq Scan on p2_c2
+                     ->  Seq Scan on p2_c3
+                     ->  Seq Scan on p2_c4
+                     ->  Seq Scan on p2_c1_c1
+                     ->  Seq Scan on p2_c1_c2
+                     ->  Seq Scan on p2_c3_c1
+                     ->  Seq Scan on p2_c3_c2
+(25 rows)
+
 SET parallel_setup_cost to DEFAULT;
 SET parallel_tuple_cost to DEFAULT;
 SET min_parallel_relation_size to DEFAULT;
@@ -464,7 +498,7 @@ error hint:
                      ->  Parallel Seq Scan on p2_c3_c2
 (27 rows)
 
--- parallelism is not available for the case
+-- parallel overrides index scan
 /*+Parallel(p1 10 hard) IndexScan(p1) */
 EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
 LOG:  pg_hint_plan:
@@ -506,6 +540,43 @@ error hint:
                      ->  Parallel Seq Scan on p2_c3_c2
 (27 rows)
 
+/*+Parallel(p1 0 hard) IndexScan(p1) */
+EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
+LOG:  pg_hint_plan:
+used hint:
+IndexScan(p1)
+Parallel(p1 0 hard)
+not used hint:
+duplication hint:
+error hint:
+
+                       QUERY PLAN                       
+--------------------------------------------------------
+ Hash Join
+   Hash Cond: (p1.id = p2.id)
+   ->  Append
+         ->  Index Scan using p1_pkey on p1
+         ->  Index Scan using p1_c1_pkey on p1_c1
+         ->  Index Scan using p1_c2_pkey on p1_c2
+         ->  Index Scan using p1_c3_pkey on p1_c3
+         ->  Index Scan using p1_c4_pkey on p1_c4
+         ->  Index Scan using p1_c1_c1_pkey on p1_c1_c1
+         ->  Index Scan using p1_c1_c2_pkey on p1_c1_c2
+         ->  Index Scan using p1_c3_c1_pkey on p1_c3_c1
+         ->  Index Scan using p1_c3_c2_pkey on p1_c3_c2
+   ->  Hash
+         ->  Append
+               ->  Seq Scan on p2
+               ->  Seq Scan on p2_c1
+               ->  Seq Scan on p2_c2
+               ->  Seq Scan on p2_c3
+               ->  Seq Scan on p2_c4
+               ->  Seq Scan on p2_c1_c1
+               ->  Seq Scan on p2_c1_c2
+               ->  Seq Scan on p2_c3_c1
+               ->  Seq Scan on p2_c3_c2
+(23 rows)
+
 -- Parallel on UNION
 EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;
          QUERY PLAN         
@@ -531,7 +602,7 @@ EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;
    ->  Seq Scan on p2_c3_c2
 (19 rows)
 
--- some of the scans are not parallel, so this cannot be parallel
+-- parallel hinting on any relation enables parallel
 SET parallel_setup_cost to 0;
 SET parallel_tuple_cost to 0;
 SET min_parallel_relation_size to 0;
@@ -570,13 +641,12 @@ error hint:
          ->  Parallel Seq Scan on p2_c3_c2
 (21 rows)
 
--- all children are parallel, so this can be parallel
-/*+Parallel(p1 10) Parallel(p2 10) */
+-- set hint also does
+/*+Set(max_parallel_workers_per_gather 1)*/
 EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;
 LOG:  pg_hint_plan:
 used hint:
-Parallel(p1 10 soft)
-Parallel(p2 10 soft)
+Set(max_parallel_workers_per_gather 1)
 not used hint:
 duplication hint:
 error hint:
@@ -606,16 +676,17 @@ error hint:
          ->  Parallel Seq Scan on p2_c3_c2
 (21 rows)
 
+-- applies largest number of workers on merged parallel paths
 SET parallel_setup_cost to DEFAULT;
 SET parallel_tuple_cost to DEFAULT;
 SET min_parallel_relation_size to DEFAULT;
-SET max_parallel_workers_per_gather to DEFAULT;
-/*+Parallel(p1 10 hard)Parallel(p2 10 hard) */
+SET max_parallel_workers_per_gather to 10;
+/*+Parallel(p1 5 hard)Parallel(p2 6 hard) */
 EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;
 LOG:  pg_hint_plan:
 used hint:
-Parallel(p1 10 hard)
-Parallel(p2 10 hard)
+Parallel(p1 5 hard)
+Parallel(p2 6 hard)
 not used hint:
 duplication hint:
 error hint:
@@ -623,7 +694,7 @@ error hint:
                 QUERY PLAN                 
 -------------------------------------------
  Gather
-   Workers Planned: 10
+   Workers Planned: 6
    ->  Append
          ->  Parallel Seq Scan on p1
          ->  Parallel Seq Scan on p1_c1
index c3988f9..2db71a9 100644 (file)
@@ -2996,26 +2996,43 @@ standard_planner_proc:
 
 /*
  * Find scan method hint to be applied to the given relation
+ *
  */
 static ScanMethodHint *
-find_scan_hint(PlannerInfo *root, Index relid, RelOptInfo *rel)
+find_scan_hint(PlannerInfo *root, Index relid)
 {
+       RelOptInfo         *rel;
        RangeTblEntry  *rte;
+       ScanMethodHint  *real_name_hint = NULL;
+       ScanMethodHint  *alias_hint = NULL;
        int                             i;
 
+       /* This should not be a join rel */
+       Assert(relid > 0);
+       rel = root->simple_rel_array[relid];
+
        /*
-        * We don't apply scan method hint if the relation is:
-        *   - not a base relation
-        *   - not an ordinary relation (such as join and subquery)
+        * This function is called for any RelOptInfo or its inheritance parent if
+        * any. If we are called from inheritance planner, the RelOptInfo for the
+        * parent of target child relation is not set in the planner info.
+        *
+        * Otherwise we should check that the reloptinfo is base relation or
+        * inheritance children.
         */
-       if (rel && (rel->reloptkind != RELOPT_BASEREL ||
-                               rel->rtekind != RTE_RELATION))
+       if (rel &&
+               rel->reloptkind != RELOPT_BASEREL &&
+               rel->reloptkind != RELOPT_OTHER_MEMBER_REL)
                return NULL;
 
+       /*
+        * This is baserel or appendrel children. We can refer to RangeTblEntry.
+        */
        rte = root->simple_rte_array[relid];
+       Assert(rte);
 
-       /* We don't force scan method of foreign tables */
-       if (rte->relkind == RELKIND_FOREIGN_TABLE)
+       /* We don't hint on other than relation and foreign tables */
+       if (rte->rtekind != RTE_RELATION ||
+               rte->relkind == RELKIND_FOREIGN_TABLE)
                return NULL;
 
        /* Find scan method hint, which matches given names, from the list. */
@@ -3027,36 +3044,70 @@ find_scan_hint(PlannerInfo *root, Index relid, RelOptInfo *rel)
                if (!hint_state_enabled(hint))
                        continue;
 
-               if (RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
-                       return hint;
+               if (!alias_hint &&
+                       RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
+                       alias_hint = hint;
+
+               /* check the real name for appendrel children */
+               if (!real_name_hint &&
+                       rel && rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
+               {
+                       char *realname = get_rel_name(rte->relid);
+
+                       if (realname && RelnameCmp(&realname, &hint->relname) == 0)
+                               real_name_hint = hint;
+               }
+
+               /* No more match expected, break  */
+               if(alias_hint && real_name_hint)
+                       break;
        }
 
-       return NULL;
+       /* real name match precedes alias match */
+       if (real_name_hint)
+               return real_name_hint;
+
+       return alias_hint;
 }
 
 static ParallelHint *
-find_parallel_hint(PlannerInfo *root, Index relid, RelOptInfo *rel)
+find_parallel_hint(PlannerInfo *root, Index relid)
 {
+       RelOptInfo         *rel;
        RangeTblEntry  *rte;
+       ParallelHint    *real_name_hint = NULL;
+       ParallelHint    *alias_hint = NULL;
        int                             i;
 
+       /* This should not be a join rel */
+       Assert(relid > 0);
+       rel = root->simple_rel_array[relid];
+
        /*
-        * We don't apply scan method hint if the relation is:
-        *   - not a base relation and inheritance children
-        *   - not an ordinary relation (such as join and subquery)
+        * This function is called for any RelOptInfo or its inheritance parent if
+        * any. If we are called from inheritance planner, the RelOptInfo for the
+        * parent of target child relation is not set in the planner info.
+        *
+        * Otherwise we should check that the reloptinfo is base relation or
+        * inheritance children.
         */
-       if (!rel || rel->rtekind != RTE_RELATION ||
-               (rel->reloptkind != RELOPT_BASEREL &&
-                rel->reloptkind != RELOPT_OTHER_MEMBER_REL))
+       if (rel &&
+               rel->reloptkind != RELOPT_BASEREL &&
+               rel->reloptkind != RELOPT_OTHER_MEMBER_REL)
                return NULL;
 
+       /*
+        * This is baserel or appendrel children. We can refer to RangeTblEntry.
+        */
        rte = root->simple_rte_array[relid];
+       Assert(rte);
 
-       /* We can't force scan method of foreign tables */
-       if (rte->relkind == RELKIND_FOREIGN_TABLE)
+       /* We don't hint on other than relation and foreign tables */
+       if (rte->rtekind != RTE_RELATION ||
+               rte->relkind == RELKIND_FOREIGN_TABLE)
                return NULL;
 
-       /* Find scan method hint, which matches given names, from the list. */
+       /* Find parallel method hint, which matches given names, from the list. */
        for (i = 0; i < current_hint_state->num_hints[HINT_TYPE_PARALLEL]; i++)
        {
                ParallelHint *hint = current_hint_state->parallel_hints[i];
@@ -3065,11 +3116,30 @@ find_parallel_hint(PlannerInfo *root, Index relid, RelOptInfo *rel)
                if (!hint_state_enabled(hint))
                        continue;
 
-               if (RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
-                       return hint;
+               if (!alias_hint &&
+                       RelnameCmp(&rte->eref->aliasname, &hint->relname) == 0)
+                       alias_hint = hint;
+
+               /* check the real name for appendrel children */
+               if (!real_name_hint &&
+                       rel && rel->reloptkind == RELOPT_OTHER_MEMBER_REL)
+               {
+                       char *realname = get_rel_name(rte->relid);
+
+                       if (realname && RelnameCmp(&realname, &hint->relname) == 0)
+                               real_name_hint = hint;
+               }
+
+               /* No more match expected, break  */
+               if(alias_hint && real_name_hint)
+                       break;
        }
 
-       return NULL;
+       /* real name match precedes alias match */
+       if (real_name_hint)
+               return real_name_hint;
+
+       return alias_hint;
 }
 
 /*
@@ -3508,10 +3578,10 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel)
                                
                /* Find hints for the parent */
                current_hint_state->parent_scan_hint =
-                       find_scan_hint(root, current_hint_state->parent_relid, NULL);
+                       find_scan_hint(root, current_hint_state->parent_relid);
 
                current_hint_state->parent_parallel_hint =
-                       find_parallel_hint(root, current_hint_state->parent_relid, NULL);
+                       find_parallel_hint(root, current_hint_state->parent_relid);
 
                /*
                 * If hint is found for the parent, apply it for this child instead
@@ -3560,10 +3630,9 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel)
                }
        }
 
-       if (current_hint_state->parent_scan_hint)
+       shint = find_scan_hint(root, rel->relid);
+       if (!shint)
                shint = current_hint_state->parent_scan_hint;
-       else
-               shint = find_scan_hint(root, rel->relid, rel);
 
        if (shint)
        {
@@ -3600,10 +3669,9 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel)
        }
 
        /* Do the same for parallel plan enforcement */
-       if (current_hint_state->parent_parallel_hint)
+       phint = find_parallel_hint(root, rel->relid);
+       if (!phint)
                phint = current_hint_state->parent_parallel_hint;
-       else
-               phint = find_parallel_hint(root, rel->relid, rel);
 
        setup_parallel_plan_enforcement(phint, current_hint_state);
 
@@ -3613,7 +3681,7 @@ setup_hint_enforcement(PlannerInfo *root, RelOptInfo *rel)
                if (debug_level > 1)
                        ereport(pg_hint_plan_message_level,
                                        (errhidestmt (true),
-                                        errmsg ("pg_hint_plan%s: get_relation_info"
+                                        errmsg ("pg_hint_plan%s: setup_hint_enforcement"
                                                         " no hint applied:"
                                                         " relation=%u(%s), inhparent=%d, current_hint=%p,"
                                                         " hint_inhibit_level=%d, scanmask=0x%x",
@@ -4126,14 +4194,10 @@ add_paths_to_joinrel_wrapper(PlannerInfo *root,
                                                         SpecialJoinInfo *sjinfo,
                                                         List *restrictlist)
 {
-       ScanMethodHint *scan_hint = NULL;
        Relids                  joinrelids;
        JoinMethodHint *join_hint;
        int                             save_nestlevel;
 
-       if ((scan_hint = find_scan_hint(root, innerrel->relid, innerrel)) != NULL)
-               setup_scan_method_enforcement(scan_hint, current_hint_state);
-
        joinrelids = bms_union(outerrel->relids, innerrel->relids);
        join_hint = find_join_hint(joinrelids);
        bms_free(joinrelids);
@@ -4168,10 +4232,6 @@ add_paths_to_joinrel_wrapper(PlannerInfo *root,
        else
                add_paths_to_joinrel(root, joinrel, outerrel, innerrel, jointype,
                                                         sjinfo, restrictlist);
-
-       /* Reset the environment if changed */
-       if (scan_hint != NULL)
-               setup_scan_method_enforcement(NULL, current_hint_state);
 }
 
 static int
@@ -4316,7 +4376,7 @@ pg_hint_plan_set_rel_pathlist(PlannerInfo * root, RelOptInfo *rel,
 
        /* Here, we regenerate paths with the current hint restriction */
 
-       /* Remove prviously paths except dummy rels */
+       /* Remove prviously generated paths */
        list_free_deep(rel->pathlist);
        rel->pathlist = NIL;
 
@@ -4328,7 +4388,7 @@ pg_hint_plan_set_rel_pathlist(PlannerInfo * root, RelOptInfo *rel,
         * estimated number of workers. Force the requested number of workers if
         * hard mode.
         */
-       phint = find_parallel_hint(root, rel->relid, rel);
+       phint = find_parallel_hint(root, rel->relid);
 
        if (phint)
        {
index 23e2f63..e7166d5 100644 (file)
@@ -8,20 +8,19 @@ SET client_min_messages TO LOG;
 CREATE TABLE s1.tl (a int);
 INSERT INTO s1.tl (SELECT a FROM generate_series(0, 100000) a);
 
--- Queries on ordinary tables
+-- Queries on ordinary tables with default setting
 EXPLAIN (COSTS false) SELECT * FROM s1.t1;
 
 SET parallel_setup_cost to 0;
 SET parallel_tuple_cost to 0;
 SET min_parallel_relation_size to 0;
+SET max_parallel_workers_per_gather to DEFAULT;
+
 /*+Parallel(t1 10)*/
 EXPLAIN (COSTS false) SELECT * FROM s1.t1;
 
 /*+Parallel(t1 10 soft)*/
 EXPLAIN (COSTS false) SELECT * FROM s1.t1;
-SET parallel_setup_cost to DEFAULT;
-SET parallel_tuple_cost to DEFAULT;
-SET min_parallel_relation_size to DEFAULT;
 
 /*+Parallel(t1 10 hard)*/
 EXPLAIN (COSTS false) SELECT * FROM s1.t1;
@@ -39,22 +38,29 @@ SET min_parallel_relation_size to DEFAULT;
 /*+Parallel(p1 10 hard)*/
 EXPLAIN (COSTS false) SELECT * FROM p1;
 
--- hinting on children don't work but enables parallel
+-- hinting on children makes the whole inheritance parallel
 /*+Parallel(p1_c1 10 hard)*/
 EXPLAIN (COSTS false) SELECT * FROM p1;
 
 
 -- Joins
-EXPLAIN (COSTS false) SELECT * FROM p1_c1 join p2_c1 on p1_c1.id = p2_c1.id;
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
 
-/*+Parallel(p1_c1 10 hard)*/
-EXPLAIN (COSTS false) SELECT * FROM p1_c1 join p2_c1 on p1_c1.id = p2_c1.id;
+/*+Parallel(p1_c1_c1 10 hard)*/
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
+
+SET parallel_setup_cost to 0;
+SET parallel_tuple_cost to 0;
+SET min_parallel_relation_size to 0;
 
-/*+Parallel(p2_c1 10 hard)*/
-EXPLAIN (COSTS false) SELECT * FROM p1_c1 join p2_c1 on p1_c1.id = p2_c1.id;
+/*+Parallel(p1_c1_c1 10 soft) Parallel(p2_c1_c1 0)*/
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
 
-/*+Parallel(p1_c1 10 hard) Parallel(p2_c1 10 hard)*/
-EXPLAIN (COSTS false) SELECT * FROM p1_c1 join p2_c1 on p1_c1.id = p2_c1.id;
+/*+Parallel(p1_c1_c1 10 hard) Parallel(p2_c1_c1 0)*/
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
+
+/*+Parallel(p1_c1_c1 10 hard) Parallel(p2_c1_c1 10 hard)*/
+EXPLAIN (COSTS false) SELECT * FROM p1_c1_c1 join p2_c1_c1 on p1_c1_c1.id = p2_c1_c1.id;
 
 
 -- Joins on inheritance tables
@@ -63,6 +69,10 @@ SET parallel_tuple_cost to 0;
 SET min_parallel_relation_size to 0;
 /*+Parallel(p1 10)*/
 EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
+
+/*+Parallel(p1 10)Parallel(p2 0)*/
+EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
+
 SET parallel_setup_cost to DEFAULT;
 SET parallel_tuple_cost to DEFAULT;
 SET min_parallel_relation_size to DEFAULT;
@@ -83,31 +93,35 @@ EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
 /*+Parallel(p1 10 hard) SeqScan(p1) */
 EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
 
--- parallelism is not available for the case
+-- parallel overrides index scan
 /*+Parallel(p1 10 hard) IndexScan(p1) */
 EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
+/*+Parallel(p1 0 hard) IndexScan(p1) */
+EXPLAIN (COSTS false) SELECT * FROM p1 join p2 on p1.id = p2.id;
 
 
 -- Parallel on UNION
 EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;
 
--- some of the scans are not parallel, so this cannot be parallel
+-- parallel hinting on any relation enables parallel
 SET parallel_setup_cost to 0;
 SET parallel_tuple_cost to 0;
 SET min_parallel_relation_size to 0;
 SET max_parallel_workers_per_gather to 0;
+
 /*+Parallel(p1 10) */
 EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;
 
--- all children are parallel, so this can be parallel
-/*+Parallel(p1 10) Parallel(p2 10) */
+-- set hint also does
+/*+Set(max_parallel_workers_per_gather 1)*/
 EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;
+
+-- applies largest number of workers on merged parallel paths
 SET parallel_setup_cost to DEFAULT;
 SET parallel_tuple_cost to DEFAULT;
 SET min_parallel_relation_size to DEFAULT;
-SET max_parallel_workers_per_gather to DEFAULT;
-
-/*+Parallel(p1 10 hard)Parallel(p2 10 hard) */
+SET max_parallel_workers_per_gather to 10;
+/*+Parallel(p1 5 hard)Parallel(p2 6 hard) */
 EXPLAIN (COSTS false) SELECT id FROM p1 UNION ALL SELECT id FROM p2;