diff options
Diffstat (limited to 'src/backend/optimizer/path/joinpath.c')
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 68 |
1 files changed, 45 insertions, 23 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index de7044de256..5aedcd15411 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -21,6 +21,7 @@ #include "optimizer/cost.h" #include "optimizer/pathnode.h" #include "optimizer/paths.h" +#include "optimizer/planmain.h" /* Hook for plugins to get control in add_paths_to_joinrel() */ set_join_pathlist_hook_type set_join_pathlist_hook = NULL; @@ -121,6 +122,35 @@ add_paths_to_joinrel(PlannerInfo *root, extra.param_source_rels = NULL; /* + * See if the inner relation is provably unique for this outer rel. + * + * We have some special cases: for JOIN_SEMI and JOIN_ANTI, it doesn't + * matter since the executor can make the equivalent optimization anyway; + * we need not expend planner cycles on proofs. For JOIN_UNIQUE_INNER, we + * know we're going to force uniqueness of the innerrel below. For + * JOIN_UNIQUE_OUTER, pass JOIN_INNER to avoid letting that value escape + * this module. + */ + switch (jointype) + { + case JOIN_SEMI: + case JOIN_ANTI: + extra.inner_unique = false; /* well, unproven */ + break; + case JOIN_UNIQUE_INNER: + extra.inner_unique = true; + break; + case JOIN_UNIQUE_OUTER: + extra.inner_unique = innerrel_is_unique(root, outerrel, innerrel, + JOIN_INNER, restrictlist); + break; + default: + extra.inner_unique = innerrel_is_unique(root, outerrel, innerrel, + jointype, restrictlist); + break; + } + + /* * Find potential mergejoin clauses. We can skip this if we are not * interested in doing a mergejoin. However, mergejoin may be our only * way of implementing a full outer join, so override enable_mergejoin if @@ -136,10 +166,10 @@ add_paths_to_joinrel(PlannerInfo *root, &mergejoin_allowed); /* - * If it's SEMI or ANTI join, compute correction factors for cost - * estimation. These will be the same for all paths. + * If it's SEMI, ANTI, or inner_unique join, compute correction factors + * for cost estimation. These will be the same for all paths. */ - if (jointype == JOIN_SEMI || jointype == JOIN_ANTI) + if (jointype == JOIN_SEMI || jointype == JOIN_ANTI || extra.inner_unique) compute_semi_anti_join_factors(root, outerrel, innerrel, jointype, sjinfo, restrictlist, &extra.semifactors); @@ -336,8 +366,7 @@ try_nestloop_path(PlannerInfo *root, * methodology worthwhile. */ initial_cost_nestloop(root, &workspace, jointype, - outer_path, inner_path, - extra->sjinfo, &extra->semifactors); + outer_path, inner_path, extra); if (add_path_precheck(joinrel, workspace.startup_cost, workspace.total_cost, @@ -348,8 +377,7 @@ try_nestloop_path(PlannerInfo *root, joinrel, jointype, &workspace, - extra->sjinfo, - &extra->semifactors, + extra, outer_path, inner_path, extra->restrictlist, @@ -399,8 +427,7 @@ try_partial_nestloop_path(PlannerInfo *root, * cost. Bail out right away if it looks terrible. */ initial_cost_nestloop(root, &workspace, jointype, - outer_path, inner_path, - extra->sjinfo, &extra->semifactors); + outer_path, inner_path, extra); if (!add_partial_path_precheck(joinrel, workspace.total_cost, pathkeys)) return; @@ -410,8 +437,7 @@ try_partial_nestloop_path(PlannerInfo *root, joinrel, jointype, &workspace, - extra->sjinfo, - &extra->semifactors, + extra, outer_path, inner_path, extra->restrictlist, @@ -486,7 +512,7 @@ try_mergejoin_path(PlannerInfo *root, initial_cost_mergejoin(root, &workspace, jointype, mergeclauses, outer_path, inner_path, outersortkeys, innersortkeys, - extra->sjinfo); + extra); if (add_path_precheck(joinrel, workspace.startup_cost, workspace.total_cost, @@ -497,7 +523,7 @@ try_mergejoin_path(PlannerInfo *root, joinrel, jointype, &workspace, - extra->sjinfo, + extra, outer_path, inner_path, extra->restrictlist, @@ -562,7 +588,7 @@ try_partial_mergejoin_path(PlannerInfo *root, initial_cost_mergejoin(root, &workspace, jointype, mergeclauses, outer_path, inner_path, outersortkeys, innersortkeys, - extra->sjinfo); + extra); if (!add_partial_path_precheck(joinrel, workspace.total_cost, pathkeys)) return; @@ -573,7 +599,7 @@ try_partial_mergejoin_path(PlannerInfo *root, joinrel, jointype, &workspace, - extra->sjinfo, + extra, outer_path, inner_path, extra->restrictlist, @@ -620,8 +646,7 @@ try_hashjoin_path(PlannerInfo *root, * never have any output pathkeys, per comments in create_hashjoin_path. */ initial_cost_hashjoin(root, &workspace, jointype, hashclauses, - outer_path, inner_path, - extra->sjinfo, &extra->semifactors); + outer_path, inner_path, extra); if (add_path_precheck(joinrel, workspace.startup_cost, workspace.total_cost, @@ -632,8 +657,7 @@ try_hashjoin_path(PlannerInfo *root, joinrel, jointype, &workspace, - extra->sjinfo, - &extra->semifactors, + extra, outer_path, inner_path, extra->restrictlist, @@ -683,8 +707,7 @@ try_partial_hashjoin_path(PlannerInfo *root, * cost. Bail out right away if it looks terrible. */ initial_cost_hashjoin(root, &workspace, jointype, hashclauses, - outer_path, inner_path, - extra->sjinfo, &extra->semifactors); + outer_path, inner_path, extra); if (!add_partial_path_precheck(joinrel, workspace.total_cost, NIL)) return; @@ -694,8 +717,7 @@ try_partial_hashjoin_path(PlannerInfo *root, joinrel, jointype, &workspace, - extra->sjinfo, - &extra->semifactors, + extra, outer_path, inner_path, extra->restrictlist, |