diff options
author | Robert Haas <rhaas@postgresql.org> | 2018-03-13 16:34:08 -0400 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2018-03-13 16:34:08 -0400 |
commit | 0927d2f46ddd4cf7d6bf2cc84b3be923e0aedc52 (patch) | |
tree | 85091a3f54d67dce66b8e2964a6d68a6d09584e6 /src/backend | |
parent | d04900de7d0cb5b6ecb6d5bf9fdb6f3105824f81 (diff) | |
download | postgresql-0927d2f46ddd4cf7d6bf2cc84b3be923e0aedc52.tar.gz postgresql-0927d2f46ddd4cf7d6bf2cc84b3be923e0aedc52.zip |
Let Parallel Append over simple UNION ALL have partial subpaths.
A simple UNION ALL gets flattened into an appendrel of subquery
RTEs, but up until now it's been impossible for the appendrel to use
the partial paths for the subqueries, so we can implement the
appendrel as a Parallel Append but only one with non-partial paths
as children.
There are three separate obstacles to removing that limitation.
First, when planning a subquery, propagate any partial paths to the
final_rel so that they are potentially visible to outer query levels
(but not if they have initPlans attached, because that wouldn't be
safe). Second, after planning a subquery, propagate any partial paths
for the final_rel to the subquery RTE in the outer query level in the
same way we do for non-partial paths. Third, teach finalize_plan() to
account for the possibility that the fake parameter we use for rescan
signalling when the plan contains a Gather (Merge) node may be
propagated from an outer query level.
Patch by me, reviewed and tested by Amit Khandekar, Rajkumar
Raghuwanshi, and Ashutosh Bapat. Test cases based on examples by
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CA+Tgmoa6L9A1nNCk3aTDVZLZ4KkHDn1+tm7mFyFvP+uQPS7bAg@mail.gmail.com
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 22 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 16 | ||||
-rw-r--r-- | src/backend/optimizer/plan/subselect.c | 17 |
3 files changed, 53 insertions, 2 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 1c792a00eb2..ea4e683abb0 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -2179,6 +2179,28 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, create_subqueryscan_path(root, rel, subpath, pathkeys, required_outer)); } + + /* If consider_parallel is false, there should be no partial paths. */ + Assert(sub_final_rel->consider_parallel || + sub_final_rel->partial_pathlist == NIL); + + /* Same for partial paths. */ + foreach(lc, sub_final_rel->partial_pathlist) + { + Path *subpath = (Path *) lfirst(lc); + List *pathkeys; + + /* Convert subpath's pathkeys to outer representation */ + pathkeys = convert_subquery_pathkeys(root, + rel, + subpath->pathkeys, + make_tlist_from_pathtarget(subpath->pathtarget)); + + /* Generate outer path using this subpath */ + add_partial_path(rel, (Path *) + create_subqueryscan_path(root, rel, subpath, + pathkeys, required_outer)); + } } /* diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 24e6c463961..66e7e7badcf 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -2195,6 +2195,22 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, } /* + * Generate partial paths for final_rel, too, if outer query levels might + * be able to make use of them. + */ + if (final_rel->consider_parallel && root->query_level > 1 && + !limit_needed(parse)) + { + Assert(!parse->rowMarks && parse->commandType == CMD_SELECT); + foreach(lc, current_rel->partial_pathlist) + { + Path *partial_path = (Path *) lfirst(lc); + + add_partial_path(final_rel, partial_path); + } + } + + /* * If there is an FDW that's responsible for all baserels of the query, * let it consider adding ForeignPaths. */ diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index dc86dd5a0b6..83008d76619 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2202,6 +2202,13 @@ SS_charge_for_initplans(PlannerInfo *root, RelOptInfo *final_rel) path->parallel_safe = false; } + /* + * Forget about any partial paths and clear consider_parallel, too; + * they're not usable if we attached an initPlan. + */ + final_rel->partial_pathlist = NIL; + final_rel->consider_parallel = false; + /* We needn't do set_cheapest() here, caller will do it */ } @@ -2407,10 +2414,16 @@ finalize_plan(PlannerInfo *root, Plan *plan, { SubqueryScan *sscan = (SubqueryScan *) plan; RelOptInfo *rel; + Bitmapset *subquery_params; - /* We must run SS_finalize_plan on the subquery */ + /* We must run finalize_plan on the subquery */ rel = find_base_rel(root, sscan->scan.scanrelid); - SS_finalize_plan(rel->subroot, sscan->subplan); + subquery_params = rel->subroot->outer_params; + if (gather_param >= 0) + subquery_params = bms_add_member(bms_copy(subquery_params), + gather_param); + finalize_plan(rel->subroot, sscan->subplan, gather_param, + subquery_params, NULL); /* Now we can add its extParams to the parent's params */ context.paramids = bms_add_members(context.paramids, |