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)
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
----------------
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:
-> 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:
-> 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
(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;
-> 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;
-> 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:
-> 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
-> 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;
-> 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:
-> 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:
QUERY PLAN
-------------------------------------------
Gather
- Workers Planned: 10
+ Workers Planned: 6
-> Append
-> Parallel Seq Scan on p1
-> Parallel Seq Scan on p1_c1
/*
* 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. */
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];
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;
}
/*
/* 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
}
}
- 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)
{
}
/* 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);
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",
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);
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
/* 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;
* 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)
{
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;
/*+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
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;
/*+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;