diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 633b5c1..87a3faf 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1447,12 +1447,14 @@ generate_mergeappend_paths(PlannerInfo *root, RelOptInfo *rel, get_cheapest_path_for_pathkeys(childrel->pathlist, pathkeys, NULL, - STARTUP_COST); + STARTUP_COST, + false); cheapest_total = get_cheapest_path_for_pathkeys(childrel->pathlist, pathkeys, NULL, - TOTAL_COST); + TOTAL_COST, + false); /* * If we can't find any paths with the right order just use the @@ -1517,7 +1519,8 @@ get_cheapest_parameterized_child_path(PlannerInfo *root, RelOptInfo *rel, cheapest = get_cheapest_path_for_pathkeys(rel->pathlist, NIL, required_outer, - TOTAL_COST); + TOTAL_COST, + false); Assert(cheapest != NULL); if (bms_equal(PATH_REQ_OUTER(cheapest), required_outer)) return cheapest; diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 2897245..3f6f233 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -936,7 +936,8 @@ generate_mergejoin_paths(PlannerInfo *root, innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist, trialsortkeys, NULL, - TOTAL_COST); + TOTAL_COST, + false); if (innerpath != NULL && (cheapest_total_inner == NULL || compare_path_costs(innerpath, cheapest_total_inner, @@ -971,7 +972,8 @@ generate_mergejoin_paths(PlannerInfo *root, innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist, trialsortkeys, NULL, - STARTUP_COST); + STARTUP_COST, + false); if (innerpath != NULL && (cheapest_startup_inner == NULL || compare_path_costs(innerpath, cheapest_startup_inner, @@ -1518,19 +1520,11 @@ hash_inner_and_outer(PlannerInfo *root, cheapest_safe_inner = cheapest_total_inner; else if (save_jointype != JOIN_UNIQUE_INNER) { - ListCell *lc; + List *paths; - foreach(lc, innerrel->cheapest_parameterized_paths) - { - Path *innerpath = (Path *) lfirst(lc); - - if (innerpath->parallel_safe && - bms_is_empty(PATH_REQ_OUTER(innerpath))) - { - cheapest_safe_inner = innerpath; - break; - } - } + paths = innerrel->cheapest_parameterized_paths; + cheapest_safe_inner = + get_cheapest_parallel_safe_total_inner(paths); } if (cheapest_safe_inner != NULL) diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index 1065b31..846929b 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -341,7 +341,8 @@ pathkeys_contained_in(List *keys1, List *keys2) Path * get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, Relids required_outer, - CostSelector cost_criterion) + CostSelector cost_criterion, + bool require_parallel_safe) { Path *matched_path = NULL; ListCell *l; @@ -358,6 +359,9 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, compare_path_costs(matched_path, path, cost_criterion) <= 0) continue; + if (require_parallel_safe && !path->parallel_safe) + continue; + if (pathkeys_contained_in(pathkeys, path->pathkeys) && bms_is_subset(PATH_REQ_OUTER(path), required_outer)) matched_path = path; @@ -407,6 +411,28 @@ get_cheapest_fractional_path_for_pathkeys(List *paths, return matched_path; } + +/* + * get_cheapest_parallel_safe_total_inner + * Find the unparameterized parallel-safe path with the least total cost. + */ +Path * +get_cheapest_parallel_safe_total_inner(List *paths) +{ + ListCell *l; + + foreach(l, paths) + { + Path *innerpath = (Path *) lfirst(l); + + if (innerpath->parallel_safe && + bms_is_empty(PATH_REQ_OUTER(innerpath))) + return innerpath; + } + + return NULL; +} + /**************************************************************************** * NEW PATHKEY FORMATION ****************************************************************************/ diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h index ebda308..bc0dcf4 100644 --- a/src/include/optimizer/paths.h +++ b/src/include/optimizer/paths.h @@ -182,11 +182,13 @@ extern PathKeysComparison compare_pathkeys(List *keys1, List *keys2); extern bool pathkeys_contained_in(List *keys1, List *keys2); extern Path *get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, Relids required_outer, - CostSelector cost_criterion); + CostSelector cost_criterion, + bool require_parallel_safe); extern Path *get_cheapest_fractional_path_for_pathkeys(List *paths, List *pathkeys, Relids required_outer, double fraction); +extern Path *get_cheapest_parallel_safe_total_inner(List *paths); extern List *build_index_pathkeys(PlannerInfo *root, IndexOptInfo *index, ScanDirection scandir); extern List *build_expression_pathkey(PlannerInfo *root, Expr *expr,