Commit 88ba0ae2 authored by Robert Haas's avatar Robert Haas

Consider Parallel Append of partial paths for UNION [ALL].

Without this patch, we can implement a UNION or UNION ALL as an
Append where Gather appears beneath one or more of the Append
branches, but this lets us put the Gather node on top, with
a partial path for each relation underneath.

There is considerably more work that could be done to improve
planning in this area, but that will probably need to wait
for a future release.

Patch by me, reviewed and tested by Ashutosh Bapat and Rajkumar
Raghuwanshi.

Discussion: http://postgr.es/m/CA+TgmoaLRAOqHmMZx=ESM3VDEPceg+-XXZsRXQ8GtFJO_zbMSw@mail.gmail.com
parent 7c91a036
...@@ -298,12 +298,18 @@ recurse_set_operations(Node *setOp, PlannerInfo *root, ...@@ -298,12 +298,18 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
*/ */
set_subquery_size_estimates(root, rel); set_subquery_size_estimates(root, rel);
/*
* Since we may want to add a partial path to this relation, we must
* set its consider_parallel flag correctly.
*/
final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
rel->consider_parallel = final_rel->consider_parallel;
/* /*
* For the moment, we consider only a single Path for the subquery. * For the moment, we consider only a single Path for the subquery.
* This should change soon (make it look more like * This should change soon (make it look more like
* set_subquery_pathlist). * set_subquery_pathlist).
*/ */
final_rel = fetch_upper_rel(subroot, UPPERREL_FINAL, NULL);
subpath = get_cheapest_fractional_path(final_rel, subpath = get_cheapest_fractional_path(final_rel,
root->tuple_fraction); root->tuple_fraction);
...@@ -320,6 +326,23 @@ recurse_set_operations(Node *setOp, PlannerInfo *root, ...@@ -320,6 +326,23 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
add_path(rel, path); add_path(rel, path);
/*
* If we have a partial path for the child relation, we can use that
* to build a partial path for this relation. But there's no point in
* considering any path but the cheapest.
*/
if (final_rel->partial_pathlist != NIL)
{
Path *partial_subpath;
Path *partial_path;
partial_subpath = linitial(final_rel->partial_pathlist);
partial_path = (Path *)
create_subqueryscan_path(root, rel, partial_subpath,
NIL, NULL);
add_partial_path(rel, partial_path);
}
/* /*
* Estimate number of groups if caller wants it. If the subquery used * Estimate number of groups if caller wants it. If the subquery used
* grouping or aggregation, its output is probably mostly unique * grouping or aggregation, its output is probably mostly unique
...@@ -552,6 +575,9 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root, ...@@ -552,6 +575,9 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
double save_fraction = root->tuple_fraction; double save_fraction = root->tuple_fraction;
ListCell *lc; ListCell *lc;
List *pathlist = NIL; List *pathlist = NIL;
List *partial_pathlist = NIL;
bool partial_paths_valid = true;
bool consider_parallel = true;
List *rellist; List *rellist;
List *tlist_list; List *tlist_list;
List *tlist; List *tlist;
...@@ -591,18 +617,34 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root, ...@@ -591,18 +617,34 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
*pTargetList = tlist; *pTargetList = tlist;
/* Build path list and relid set. */ /* Build path lists and relid set. */
foreach(lc, rellist) foreach(lc, rellist)
{ {
RelOptInfo *rel = lfirst(lc); RelOptInfo *rel = lfirst(lc);
pathlist = lappend(pathlist, rel->cheapest_total_path); pathlist = lappend(pathlist, rel->cheapest_total_path);
if (consider_parallel)
{
if (!rel->consider_parallel)
{
consider_parallel = false;
partial_paths_valid = false;
}
else if (rel->partial_pathlist == NIL)
partial_paths_valid = false;
else
partial_pathlist = lappend(partial_pathlist,
linitial(rel->partial_pathlist));
}
relids = bms_union(relids, rel->relids); relids = bms_union(relids, rel->relids);
} }
/* Build result relation. */ /* Build result relation. */
result_rel = fetch_upper_rel(root, UPPERREL_SETOP, relids); result_rel = fetch_upper_rel(root, UPPERREL_SETOP, relids);
result_rel->reltarget = create_pathtarget(root, tlist); result_rel->reltarget = create_pathtarget(root, tlist);
result_rel->consider_parallel = consider_parallel;
/* /*
* Append the child results together. * Append the child results together.
...@@ -626,6 +668,53 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root, ...@@ -626,6 +668,53 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root,
*/ */
result_rel->rows = path->rows; result_rel->rows = path->rows;
/*
* Now consider doing the same thing using the partial paths plus Append
* plus Gather.
*/
if (partial_paths_valid)
{
Path *ppath;
ListCell *lc;
int parallel_workers = 0;
/* Find the highest number of workers requested for any subpath. */
foreach(lc, partial_pathlist)
{
Path *path = lfirst(lc);
parallel_workers = Max(parallel_workers, path->parallel_workers);
}
Assert(parallel_workers > 0);
/*
* If the use of parallel append is permitted, always request at least
* log2(# of children) paths. We assume it can be useful to have
* extra workers in this case because they will be spread out across
* the children. The precise formula is just a guess; see
* add_paths_to_append_rel.
*/
if (enable_parallel_append)
{
parallel_workers = Max(parallel_workers,
fls(list_length(partial_pathlist)));
parallel_workers = Min(parallel_workers,
max_parallel_workers_per_gather);
}
Assert(parallel_workers > 0);
ppath = (Path *)
create_append_path(result_rel, NIL, partial_pathlist,
NULL, parallel_workers, enable_parallel_append,
NIL, -1);
ppath = (Path *)
create_gather_path(root, result_rel, ppath,
result_rel->reltarget, NULL, NULL);
if (!op->all)
ppath = make_union_unique(op, ppath, tlist, root);
add_path(result_rel, ppath);
}
/* Undo effects of possibly forcing tuple_fraction to 0 */ /* Undo effects of possibly forcing tuple_fraction to 0 */
root->tuple_fraction = save_fraction; root->tuple_fraction = save_fraction;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment