diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 255f56b827..544afa2781 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1296,19 +1296,17 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, { List *subpaths = NIL; bool subpaths_valid = true; - List *partial_subpaths = NIL; - List *pa_partial_subpaths = NIL; - List *pa_nonpartial_subpaths = NIL; - bool partial_subpaths_valid = true; - bool pa_subpaths_valid; + List *parallel_partial_subpaths = NIL; + List *parallel_nonpartial_subpaths = NIL; + bool parallel_subpaths_valid = true; List *all_child_pathkeys = NIL; List *all_child_outers = NIL; ListCell *l; List *partitioned_rels = NIL; double partial_rows = -1; + bool allow_parallel_append; - /* If appropriate, consider parallel append */ - pa_subpaths_valid = enable_parallel_append && rel->consider_parallel; + allow_parallel_append = enable_parallel_append && rel->consider_parallel; /* * AppendPath generated for partitioned tables must record the RT indexes @@ -1366,7 +1364,6 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, { RelOptInfo *childrel = lfirst(l); ListCell *lcp; - Path *cheapest_partial_path = NULL; /* * For UNION ALLs with non-empty partitioned_child_rels, accumulate @@ -1391,31 +1388,31 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, else subpaths_valid = false; - /* Same idea, but for a partial plan. */ - if (childrel->partial_pathlist != NIL) - { - cheapest_partial_path = linitial(childrel->partial_pathlist); - accumulate_append_subpath(cheapest_partial_path, - &partial_subpaths, NULL); - } - else - partial_subpaths_valid = false; - /* - * Same idea, but for a parallel append mixing partial and non-partial - * paths. + * We also build a set of paths for each child by trying to use the + * cheapest partial path, or the cheapest parallel safe normal path + * either when that is cheaper, or if parallel append is not allowed. */ - if (pa_subpaths_valid) + if (parallel_subpaths_valid) { Path *nppath = NULL; + Path *cheapest_partial_path = NULL; - nppath = - get_cheapest_parallel_safe_total_inner(childrel->pathlist); + /* + * Only attempt to use a parallel safe subplan when parallel + * append is allowed. + */ + if (allow_parallel_append) + nppath = + get_cheapest_parallel_safe_total_inner(childrel->pathlist); + + if (childrel->partial_pathlist != NIL) + cheapest_partial_path = linitial(childrel->partial_pathlist); if (cheapest_partial_path == NULL && nppath == NULL) { /* Neither a partial nor a parallel-safe path? Forget it. */ - pa_subpaths_valid = false; + parallel_subpaths_valid = false; } else if (nppath == NULL || (cheapest_partial_path != NULL && @@ -1424,8 +1421,8 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, /* Partial path is cheaper or the only option. */ Assert(cheapest_partial_path != NULL); accumulate_append_subpath(cheapest_partial_path, - &pa_partial_subpaths, - &pa_nonpartial_subpaths); + ¶llel_partial_subpaths, + ¶llel_nonpartial_subpaths); } else @@ -1444,7 +1441,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, * figure that out. */ accumulate_append_subpath(nppath, - &pa_nonpartial_subpaths, + ¶llel_nonpartial_subpaths, NULL); } } @@ -1525,23 +1522,28 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, partitioned_rels, -1)); /* - * Consider an append of unordered, unparameterized partial paths. Make - * it parallel-aware if possible. + * Add a partial append path for the list of partial and parallel-safe + * subpaths that we collected above. We perform a parallel append on + * these, when allowed. We don't attempt to consider both a parallel and + * non-parallel append as we assume a parallel append will always come out + * the cheaper of the two partial path options. */ - if (partial_subpaths_valid && partial_subpaths != NIL) + if (parallel_subpaths_valid) { AppendPath *appendpath; ListCell *lc; int parallel_workers = 0; - /* Find the highest number of workers requested for any subpath. */ - foreach(lc, partial_subpaths) + /* + * Find the highest number of workers requested for any partial + * subpath. + */ + foreach(lc, parallel_partial_subpaths) { 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 @@ -1552,19 +1554,20 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, * partitions vs. an unpartitioned table with the same data, so the * use of some kind of log-scaling here seems to make some sense. */ - if (enable_parallel_append) + if (allow_parallel_append) { parallel_workers = Max(parallel_workers, fls(list_length(live_childrels))); parallel_workers = Min(parallel_workers, max_parallel_workers_per_gather); + Assert(parallel_workers > 0); } - Assert(parallel_workers > 0); - /* Generate a partial append path. */ - appendpath = create_append_path(root, rel, NIL, partial_subpaths, + appendpath = create_append_path(root, rel, + parallel_nonpartial_subpaths, + parallel_partial_subpaths, NIL, NULL, parallel_workers, - enable_parallel_append, + allow_parallel_append, partitioned_rels, -1); /* @@ -1573,48 +1576,6 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel, */ partial_rows = appendpath->path.rows; - /* Add the path. */ - add_partial_path(rel, (Path *) appendpath); - } - - /* - * Consider a parallel-aware append using a mix of partial and non-partial - * paths. (This only makes sense if there's at least one child which has - * a non-partial path that is substantially cheaper than any partial path; - * otherwise, we should use the append path added in the previous step.) - */ - if (pa_subpaths_valid && pa_nonpartial_subpaths != NIL) - { - AppendPath *appendpath; - ListCell *lc; - int parallel_workers = 0; - - /* - * Find the highest number of workers requested for any partial - * subpath. - */ - foreach(lc, pa_partial_subpaths) - { - Path *path = lfirst(lc); - - parallel_workers = Max(parallel_workers, path->parallel_workers); - } - - /* - * Same formula here as above. It's even more important in this - * instance because the non-partial paths won't contribute anything to - * the planned number of parallel workers. - */ - parallel_workers = Max(parallel_workers, - fls(list_length(live_childrels))); - parallel_workers = Min(parallel_workers, - max_parallel_workers_per_gather); - Assert(parallel_workers > 0); - - appendpath = create_append_path(root, rel, pa_nonpartial_subpaths, - pa_partial_subpaths, - NIL, NULL, parallel_workers, true, - partitioned_rels, partial_rows); add_partial_path(rel, (Path *) appendpath); }