diff options
Diffstat (limited to 'src/backend/optimizer/path/joinpath.c')
-rw-r--r-- | src/backend/optimizer/path/joinpath.c | 171 |
1 files changed, 83 insertions, 88 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index b02f67ba1f6..ab3f902f02b 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.95 2005/06/05 22:32:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.96 2005/10/15 02:49:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -65,9 +65,9 @@ add_paths_to_joinrel(PlannerInfo *root, /* * Find potential mergejoin clauses. We can skip this if we are not - * interested in doing a mergejoin. However, mergejoin is currently - * our only way of implementing full outer joins, so override - * mergejoin disable if it's a full join. + * interested in doing a mergejoin. However, mergejoin is currently our + * only way of implementing full outer joins, so override mergejoin + * disable if it's a full join. */ if (enable_mergejoin || jointype == JOIN_FULL) mergeclause_list = select_mergejoin_clauses(joinrel, @@ -95,23 +95,22 @@ add_paths_to_joinrel(PlannerInfo *root, /* * 3. Consider paths where the inner relation need not be explicitly - * sorted. This includes mergejoins only (nestloops were already - * built in match_unsorted_outer). + * sorted. This includes mergejoins only (nestloops were already built in + * match_unsorted_outer). * * Diked out as redundant 2/13/2000 -- tgl. There isn't any really - * significant difference between the inner and outer side of a - * mergejoin, so match_unsorted_inner creates no paths that aren't - * equivalent to those made by match_unsorted_outer when - * add_paths_to_joinrel() is invoked with the two rels given in the - * other order. + * significant difference between the inner and outer side of a mergejoin, + * so match_unsorted_inner creates no paths that aren't equivalent to + * those made by match_unsorted_outer when add_paths_to_joinrel() is + * invoked with the two rels given in the other order. */ match_unsorted_inner(root, joinrel, outerrel, innerrel, restrictlist, mergeclause_list, jointype); #endif /* - * 4. Consider paths where both outer and inner relations must be - * hashed before being joined. + * 4. Consider paths where both outer and inner relations must be hashed + * before being joined. */ if (enable_hashjoin) hash_inner_and_outer(root, joinrel, outerrel, innerrel, @@ -174,11 +173,11 @@ sort_inner_and_outer(PlannerInfo *root, /* * We only consider the cheapest-total-cost input paths, since we are * assuming here that a sort is required. We will consider - * cheapest-startup-cost input paths later, and only if they don't - * need a sort. + * cheapest-startup-cost input paths later, and only if they don't need a + * sort. * - * If unique-ification is requested, do it and then handle as a plain - * inner join. + * If unique-ification is requested, do it and then handle as a plain inner + * join. */ outer_path = outerrel->cheapest_total_path; inner_path = innerrel->cheapest_total_path; @@ -194,31 +193,29 @@ sort_inner_and_outer(PlannerInfo *root, } /* - * Each possible ordering of the available mergejoin clauses will - * generate a differently-sorted result path at essentially the same - * cost. We have no basis for choosing one over another at this level - * of joining, but some sort orders may be more useful than others for - * higher-level mergejoins, so it's worth considering multiple - * orderings. + * Each possible ordering of the available mergejoin clauses will generate + * a differently-sorted result path at essentially the same cost. We have + * no basis for choosing one over another at this level of joining, but + * some sort orders may be more useful than others for higher-level + * mergejoins, so it's worth considering multiple orderings. * * Actually, it's not quite true that every mergeclause ordering will * generate a different path order, because some of the clauses may be - * redundant. Therefore, what we do is convert the mergeclause list - * to a list of canonical pathkeys, and then consider different - * orderings of the pathkeys. + * redundant. Therefore, what we do is convert the mergeclause list to a + * list of canonical pathkeys, and then consider different orderings of + * the pathkeys. * * Generating a path for *every* permutation of the pathkeys doesn't seem * like a winning strategy; the cost in planning time is too high. For - * now, we generate one path for each pathkey, listing that pathkey - * first and the rest in random order. This should allow at least a - * one-clause mergejoin without re-sorting against any other possible - * mergejoin partner path. But if we've not guessed the right - * ordering of secondary keys, we may end up evaluating clauses as - * qpquals when they could have been done as mergeclauses. We need to - * figure out a better way. (Two possible approaches: look at all the - * relevant index relations to suggest plausible sort orders, or make - * just one output path and somehow mark it as having a sort-order - * that can be rearranged freely.) + * now, we generate one path for each pathkey, listing that pathkey first + * and the rest in random order. This should allow at least a one-clause + * mergejoin without re-sorting against any other possible mergejoin + * partner path. But if we've not guessed the right ordering of secondary + * keys, we may end up evaluating clauses as qpquals when they could have + * been done as mergeclauses. We need to figure out a better way. (Two + * possible approaches: look at all the relevant index relations to + * suggest plausible sort orders, or make just one output path and somehow + * mark it as having a sort-order that can be rearranged freely.) */ all_pathkeys = make_pathkeys_for_mergeclauses(root, mergeclause_list, @@ -243,26 +240,25 @@ sort_inner_and_outer(PlannerInfo *root, /* * Select mergeclause(s) that match this sort ordering. If we had - * redundant merge clauses then we will get a subset of the - * original clause list. There had better be some match, - * however... + * redundant merge clauses then we will get a subset of the original + * clause list. There had better be some match, however... */ cur_mergeclauses = find_mergeclauses_for_pathkeys(root, cur_pathkeys, - mergeclause_list); + mergeclause_list); Assert(cur_mergeclauses != NIL); /* Forget it if can't use all the clauses in right/full join */ if (useallclauses && - list_length(cur_mergeclauses) != list_length(mergeclause_list)) + list_length(cur_mergeclauses) != list_length(mergeclause_list)) continue; /* * Build sort pathkeys for both sides. * * Note: it's possible that the cheapest paths will already be sorted - * properly. create_mergejoin_path will detect that case and - * suppress an explicit sort step, so we needn't do so here. + * properly. create_mergejoin_path will detect that case and suppress + * an explicit sort step, so we needn't do so here. */ outerkeys = make_pathkeys_for_mergeclauses(root, cur_mergeclauses, @@ -343,10 +339,10 @@ match_unsorted_outer(PlannerInfo *root, /* * Nestloop only supports inner, left, and IN joins. Also, if we are - * doing a right or full join, we must use *all* the mergeclauses as - * join clauses, else we will not have a valid plan. (Although these - * two flags are currently inverses, keep them separate for clarity - * and possible future changes.) + * doing a right or full join, we must use *all* the mergeclauses as join + * clauses, else we will not have a valid plan. (Although these two flags + * are currently inverses, keep them separate for clarity and possible + * future changes.) */ switch (jointype) { @@ -385,10 +381,9 @@ match_unsorted_outer(PlannerInfo *root, else if (nestjoinOK) { /* - * If the cheapest inner path is a join or seqscan, we should - * consider materializing it. (This is a heuristic: we could - * consider it always, but for inner indexscans it's probably a - * waste of time.) + * If the cheapest inner path is a join or seqscan, we should consider + * materializing it. (This is a heuristic: we could consider it + * always, but for inner indexscans it's probably a waste of time.) */ if (!(IsA(inner_cheapest_total, IndexPath) || IsA(inner_cheapest_total, BitmapHeapPath) || @@ -397,8 +392,8 @@ match_unsorted_outer(PlannerInfo *root, create_material_path(innerrel, inner_cheapest_total); /* - * Get the best innerjoin indexpath (if any) for this outer rel. - * It's the same for all outer paths. + * Get the best innerjoin indexpath (if any) for this outer rel. It's + * the same for all outer paths. */ bestinnerjoin = best_inner_indexscan(root, innerrel, outerrel->relids, jointype); @@ -417,8 +412,8 @@ match_unsorted_outer(PlannerInfo *root, int sortkeycnt; /* - * If we need to unique-ify the outer path, it's pointless to - * consider any but the cheapest outer. + * If we need to unique-ify the outer path, it's pointless to consider + * any but the cheapest outer. */ if (save_jointype == JOIN_UNIQUE_OUTER) { @@ -429,9 +424,9 @@ match_unsorted_outer(PlannerInfo *root, } /* - * The result will have this sort order (even if it is implemented - * as a nestloop, and even if some of the mergeclauses are - * implemented by qpquals rather than as true mergeclauses): + * The result will have this sort order (even if it is implemented as + * a nestloop, and even if some of the mergeclauses are implemented by + * qpquals rather than as true mergeclauses): */ merge_pathkeys = build_join_pathkeys(root, joinrel, jointype, outerpath->pathkeys); @@ -516,9 +511,9 @@ match_unsorted_outer(PlannerInfo *root, innerrel); /* - * Generate a mergejoin on the basis of sorting the cheapest - * inner. Since a sort will be needed, only cheapest total cost - * matters. (But create_mergejoin_path will do the right thing if + * Generate a mergejoin on the basis of sorting the cheapest inner. + * Since a sort will be needed, only cheapest total cost matters. + * (But create_mergejoin_path will do the right thing if * inner_cheapest_total is already correctly sorted.) */ add_path(joinrel, (Path *) @@ -538,10 +533,10 @@ match_unsorted_outer(PlannerInfo *root, continue; /* - * Look for presorted inner paths that satisfy the innersortkey - * list --- or any truncation thereof, if we are allowed to build - * a mergejoin using a subset of the merge clauses. Here, we - * consider both cheap startup cost and cheap total cost. Ignore + * Look for presorted inner paths that satisfy the innersortkey list + * --- or any truncation thereof, if we are allowed to build a + * mergejoin using a subset of the merge clauses. Here, we consider + * both cheap startup cost and cheap total cost. Ignore * inner_cheapest_total, since we already made a path with it. */ num_sortkeys = list_length(innersortkeys); @@ -559,8 +554,8 @@ match_unsorted_outer(PlannerInfo *root, /* * Look for an inner path ordered well enough for the first - * 'sortkeycnt' innersortkeys. NB: trialsortkeys list is - * modified destructively, which is why we made a copy... + * 'sortkeycnt' innersortkeys. NB: trialsortkeys list is modified + * destructively, which is why we made a copy... */ trialsortkeys = list_truncate(trialsortkeys, sortkeycnt); innerpath = get_cheapest_path_for_pathkeys(innerrel->pathlist, @@ -611,8 +606,8 @@ match_unsorted_outer(PlannerInfo *root, if (innerpath != cheapest_total_inner) { /* - * Avoid rebuilding clause list if we already made - * one; saves memory in big join trees... + * Avoid rebuilding clause list if we already made one; + * saves memory in big join trees... */ if (newclauses == NIL) { @@ -620,8 +615,8 @@ match_unsorted_outer(PlannerInfo *root, { newclauses = find_mergeclauses_for_pathkeys(root, - trialsortkeys, - mergeclauses); + trialsortkeys, + mergeclauses); Assert(newclauses != NIL); } else @@ -697,8 +692,8 @@ hash_inner_and_outer(PlannerInfo *root, * We need to build only one hashpath for any given pair of outer and * inner relations; all of the hashable clauses will be used as keys. * - * Scan the join's restrictinfo list to find hashjoinable clauses that - * are usable with this pair of sub-relations. + * Scan the join's restrictinfo list to find hashjoinable clauses that are + * usable with this pair of sub-relations. */ hashclauses = NIL; foreach(l, restrictlist) @@ -725,7 +720,7 @@ hash_inner_and_outer(PlannerInfo *root, /* righthand side is inner */ } else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) && - bms_is_subset(restrictinfo->right_relids, outerrel->relids)) + bms_is_subset(restrictinfo->right_relids, outerrel->relids)) { /* lefthand side is inner */ } @@ -739,9 +734,9 @@ hash_inner_and_outer(PlannerInfo *root, if (hashclauses) { /* - * We consider both the cheapest-total-cost and - * cheapest-startup-cost outer paths. There's no need to consider - * any but the cheapest-total-cost inner path, however. + * We consider both the cheapest-total-cost and cheapest-startup-cost + * outer paths. There's no need to consider any but the + * cheapest-total-cost inner path, however. */ Path *cheapest_startup_outer = outerrel->cheapest_startup_path; Path *cheapest_total_outer = outerrel->cheapest_total_path; @@ -807,15 +802,15 @@ select_mergejoin_clauses(RelOptInfo *joinrel, RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l); /* - * If processing an outer join, only use its own join clauses in - * the merge. For inner joins we need not be so picky. + * If processing an outer join, only use its own join clauses in the + * merge. For inner joins we need not be so picky. * - * Furthermore, if it is a right/full join then *all* the explicit - * join clauses must be mergejoinable, else the executor will - * fail. If we are asked for a right join then just return NIL to - * indicate no mergejoin is possible (we can handle it as a left - * join instead). If we are asked for a full join then emit an - * error, because there is no fallback. + * Furthermore, if it is a right/full join then *all* the explicit join + * clauses must be mergejoinable, else the executor will fail. If we + * are asked for a right join then just return NIL to indicate no + * mergejoin is possible (we can handle it as a left join instead). If + * we are asked for a full join then emit an error, because there is + * no fallback. */ if (isouterjoin) { @@ -847,8 +842,8 @@ select_mergejoin_clauses(RelOptInfo *joinrel, /* * Check if clause is usable with these input rels. All the vars - * needed on each side of the clause must be available from one or - * the other of the input rels. + * needed on each side of the clause must be available from one or the + * other of the input rels. */ if (bms_is_subset(restrictinfo->left_relids, outerrel->relids) && bms_is_subset(restrictinfo->right_relids, innerrel->relids)) @@ -856,7 +851,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel, /* righthand side is inner */ } else if (bms_is_subset(restrictinfo->left_relids, innerrel->relids) && - bms_is_subset(restrictinfo->right_relids, outerrel->relids)) + bms_is_subset(restrictinfo->right_relids, outerrel->relids)) { /* lefthand side is inner */ } |