mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Add a Gather Merge executor node.
Like Gather, we spawn multiple workers and run the same plan in each one; however, Gather Merge is used when each worker produces the same output ordering and we want to preserve that output ordering while merging together the streams of tuples from various workers. (In a way, Gather Merge is like a hybrid of Gather and MergeAppend.) This works out to a win if it saves us from having to perform an expensive Sort. In cases where only a small amount of data would need to be sorted, it may actually be faster to use a regular Gather node and then sort the results afterward, because Gather Merge sometimes needs to wait synchronously for tuples whereas a pure Gather generally doesn't. But if this avoids an expensive sort then it's a win. Rushabh Lathia, reviewed and tested by Amit Kapila, Thomas Munro, and Neha Sharma, and reviewed and revised by me. Discussion: http://postgr.es/m/CAGPqQf09oPX-cQRpBKS0Gq49Z+m6KBxgxd_p9gX8CKk_d75HoQ@mail.gmail.com
This commit is contained in:
@ -1627,6 +1627,66 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||
return pathnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* create_gather_merge_path
|
||||
*
|
||||
* Creates a path corresponding to a gather merge scan, returning
|
||||
* the pathnode.
|
||||
*/
|
||||
GatherMergePath *
|
||||
create_gather_merge_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||
PathTarget *target, List *pathkeys,
|
||||
Relids required_outer, double *rows)
|
||||
{
|
||||
GatherMergePath *pathnode = makeNode(GatherMergePath);
|
||||
Cost input_startup_cost = 0;
|
||||
Cost input_total_cost = 0;
|
||||
|
||||
Assert(subpath->parallel_safe);
|
||||
Assert(pathkeys);
|
||||
|
||||
pathnode->path.pathtype = T_GatherMerge;
|
||||
pathnode->path.parent = rel;
|
||||
pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
|
||||
required_outer);
|
||||
pathnode->path.parallel_aware = false;
|
||||
|
||||
pathnode->subpath = subpath;
|
||||
pathnode->num_workers = subpath->parallel_workers;
|
||||
pathnode->path.pathkeys = pathkeys;
|
||||
pathnode->path.pathtarget = target ? target : rel->reltarget;
|
||||
pathnode->path.rows += subpath->rows;
|
||||
|
||||
if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
|
||||
{
|
||||
/* Subpath is adequately ordered, we won't need to sort it */
|
||||
input_startup_cost += subpath->startup_cost;
|
||||
input_total_cost += subpath->total_cost;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We'll need to insert a Sort node, so include cost for that */
|
||||
Path sort_path; /* dummy for result of cost_sort */
|
||||
|
||||
cost_sort(&sort_path,
|
||||
root,
|
||||
pathkeys,
|
||||
subpath->total_cost,
|
||||
subpath->rows,
|
||||
subpath->pathtarget->width,
|
||||
0.0,
|
||||
work_mem,
|
||||
-1);
|
||||
input_startup_cost += sort_path.startup_cost;
|
||||
input_total_cost += sort_path.total_cost;
|
||||
}
|
||||
|
||||
cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
|
||||
input_startup_cost, input_total_cost, rows);
|
||||
|
||||
return pathnode;
|
||||
}
|
||||
|
||||
/*
|
||||
* translate_sub_tlist - get subquery column numbers represented by tlist
|
||||
*
|
||||
|
Reference in New Issue
Block a user