From b2e1d7bcdc3bd6ef67cf2426a42c3fb96559ec97 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 12 Mar 2018 16:45:15 -0400 Subject: [PATCH 4/5] Postpone generate_gather_paths for topmost scan/join rel. Don't call generate_gather_paths for the topmost scan/join relation when it is initially populated with paths. If the scan/join target is parallel-safe, we actually skip this for the topmost scan/join rel altogether and instead do it for the tlist_rel, so that the projection is done in the worker and costs are computed accordingly. Amit Kapila and Robert Haas --- src/backend/optimizer/geqo/geqo_eval.c | 21 ++++++++++++++------- src/backend/optimizer/path/allpaths.c | 26 +++++++++++++++++++------- src/backend/optimizer/plan/planner.c | 16 ++++++++++++++++ 3 files changed, 49 insertions(+), 14 deletions(-) diff --git a/src/backend/optimizer/geqo/geqo_eval.c b/src/backend/optimizer/geqo/geqo_eval.c index 0be2a73e05..3ef7d7d8aa 100644 --- a/src/backend/optimizer/geqo/geqo_eval.c +++ b/src/backend/optimizer/geqo/geqo_eval.c @@ -40,7 +40,7 @@ typedef struct } Clump; static List *merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, - bool force); + int num_gene, bool force); static bool desirable_join(PlannerInfo *root, RelOptInfo *outer_rel, RelOptInfo *inner_rel); @@ -196,7 +196,7 @@ gimme_tree(PlannerInfo *root, Gene *tour, int num_gene) cur_clump->size = 1; /* Merge it into the clumps list, using only desirable joins */ - clumps = merge_clump(root, clumps, cur_clump, false); + clumps = merge_clump(root, clumps, cur_clump, num_gene, false); } if (list_length(clumps) > 1) @@ -210,7 +210,7 @@ gimme_tree(PlannerInfo *root, Gene *tour, int num_gene) { Clump *clump = (Clump *) lfirst(lc); - fclumps = merge_clump(root, fclumps, clump, true); + fclumps = merge_clump(root, fclumps, clump, num_gene, true); } clumps = fclumps; } @@ -235,7 +235,8 @@ gimme_tree(PlannerInfo *root, Gene *tour, int num_gene) * "desirable" joins. */ static List * -merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, bool force) +merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, int num_gene, + bool force) { ListCell *prev; ListCell *lc; @@ -267,8 +268,14 @@ merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, bool force) /* Create paths for partitionwise joins. */ generate_partitionwise_join_paths(root, joinrel); - /* Create GatherPaths for any useful partial paths for rel */ - generate_gather_paths(root, joinrel, false); + /* + * Except for the topmost scan/join rel, consider gathering + * partial paths. We'll do the same for the topmost scan/join + * rel once we know the final targetlist (see + * grouping_planner). + */ + if (old_clump->size + new_clump->size < num_gene) + generate_gather_paths(root, joinrel, false); /* Find and save the cheapest paths for this joinrel */ set_cheapest(joinrel); @@ -286,7 +293,7 @@ merge_clump(PlannerInfo *root, List *clumps, Clump *new_clump, bool force) * others. When no further merge is possible, we'll reinsert * it into the list. */ - return merge_clump(root, clumps, old_clump, force); + return merge_clump(root, clumps, old_clump, num_gene, force); } } prev = lc; diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 1c792a00eb..9a4d995d25 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -481,13 +481,20 @@ set_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, } /* - * If this is a baserel, consider gathering any partial paths we may have - * created for it. (If we tried to gather inheritance children, we could + * If this is a baserel, we should normally consider gathering any partial + * paths we may have created for it. + * + * However, if this is an inheritance child, skip it. Otherwise, we could * end up with a very large number of gather nodes, each trying to grab - * its own pool of workers, so don't do this for otherrels. Instead, - * we'll consider gathering partial paths for the parent appendrel.) + * its own pool of workers. Instead, we'll consider gathering partial + * paths for the parent appendrel. + * + * Also, if this is the topmost scan/join rel (that is, the only baserel), + * we postpone this until the final scan/join targelist is available (see + * grouping_planner). */ - if (rel->reloptkind == RELOPT_BASEREL) + if (rel->reloptkind == RELOPT_BASEREL && + bms_membership(root->all_baserels) != BMS_SINGLETON) generate_gather_paths(root, rel, false); /* @@ -2668,8 +2675,13 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels) /* Create paths for partitionwise joins. */ generate_partitionwise_join_paths(root, rel); - /* Create GatherPaths for any useful partial paths for rel */ - generate_gather_paths(root, rel, false); + /* + * Except for the topmost scan/join rel, consider gathering + * partial paths. We'll do the same for the topmost scan/join rel + * once we know the final targetlist (see grouping_planner). + */ + if (lev < levels_needed) + generate_gather_paths(root, rel, false); /* Find and save the cheapest paths for this rel */ set_cheapest(rel); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 7532990548..9d33306783 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -1884,6 +1884,8 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, tlist_rel = fetch_upper_rel(root, UPPERREL_TLIST, NULL); tlist_rel->consider_parallel = current_rel->consider_parallel && scanjoin_target_parallel_safe; + tlist_rel->reltarget = scanjoin_target; + tlist_rel->rows = current_rel->rows; /* * If there are any SRFs in the targetlist, we must separate each of @@ -1927,6 +1929,16 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, scanjoin_targets = scanjoin_targets_contain_srfs = NIL; } + /* + * If the final scan/join target is not parallel-safe, we must + * generate Gather paths now, since no partial paths will be generated + * for tlist_rel. Otherwise, the paths generated from tlist_rel will + * be superior to these in that projection will be done in by each + * participant rather than only in the leader, so skip this for now. + */ + if (!scanjoin_target_parallel_safe) + generate_gather_paths(root, current_rel, false); + /* * Apply SRF-free scan/join target to all Paths for the scanjoin rel * to produce paths for the tlist rel. @@ -1971,6 +1983,10 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, scanjoin_targets, scanjoin_targets_contain_srfs); + /* Generate Gather and Gather Merge paths, if appropriate. */ + if (tlist_rel->consider_parallel) + generate_gather_paths(root, tlist_rel, false); + /* Now consider the tlist_rel to be the current upper relation. */ set_cheapest(tlist_rel); current_rel = tlist_rel; -- 2.14.3 (Apple Git-98)