diff options
Diffstat (limited to 'src/backend/optimizer/path/joinpath.c')
| -rw-r--r-- | src/backend/optimizer/path/joinpath.c | 137 |
1 files changed, 39 insertions, 98 deletions
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 450bc26bed..62724e6244 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.101 2006/02/04 23:03:20 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/path/joinpath.c,v 1.102 2006/02/05 02:59:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -35,9 +35,8 @@ static void match_unsorted_outer(PlannerInfo *root, RelOptInfo *joinrel, static void hash_inner_and_outer(PlannerInfo *root, RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, List *restrictlist, JoinType jointype); -static void join_before_append(PlannerInfo *root, RelOptInfo *joinrel, - RelOptInfo *outerrel, RelOptInfo *innerrel, - JoinType jointype); +static Path *best_appendrel_indexscan(PlannerInfo *root, RelOptInfo *rel, + Relids outer_relids, JoinType jointype); static List *select_mergejoin_clauses(RelOptInfo *joinrel, RelOptInfo *outerrel, RelOptInfo *innerrel, @@ -118,13 +117,6 @@ add_paths_to_joinrel(PlannerInfo *root, if (enable_hashjoin) hash_inner_and_outer(root, joinrel, outerrel, innerrel, restrictlist, jointype); - - /* - * 5. If the inner relation is an append relation, consider joining - * the outer rel to each append member and then appending the results. - */ - if (innerrel->cheapest_total_path->pathtype == T_Append) - join_before_append(root, joinrel, outerrel, innerrel, jointype); } /* @@ -405,8 +397,17 @@ match_unsorted_outer(PlannerInfo *root, * 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); + if (innerrel->reloptkind != RELOPT_JOINREL) + { + if (IsA(inner_cheapest_total, AppendPath)) + bestinnerjoin = best_appendrel_indexscan(root, innerrel, + outerrel->relids, + jointype); + else if (innerrel->rtekind == RTE_RELATION) + bestinnerjoin = best_inner_indexscan(root, innerrel, + outerrel->relids, + jointype); + } } foreach(l, outerrel->pathlist) @@ -788,75 +789,27 @@ hash_inner_and_outer(PlannerInfo *root, } /* - * join_before_append - * Creates possible join paths for processing a single join relation - * 'joinrel' when the inner input is an append relation. - * - * The idea here is to swap the order of the APPEND and JOIN operators. - * This is only really helpful if it allows us to reduce the cost of - * scanning the members of the append relation, and so we only consider - * plans involving nestloops with inner indexscans. Also, since the APPEND - * will certainly yield an unsorted result, there's no point in considering - * any but the cheapest-total outer path. - * - * XXX this is a bit of a kluge, because the resulting plan has to evaluate - * the outer relation multiple times. Would be better to allow - * best_inner_indexscan to generate an AppendPath and not have this routine - * at all. But we can't do that without some executor changes (need a way - * to pass outer keys down through Append). FIXME later. - * - * 'joinrel' is the join relation - * 'outerrel' is the outer join relation - * 'innerrel' is the inner join relation - * 'jointype' is the type of join to do + * best_appendrel_indexscan + * Finds the best available set of inner indexscans for a nestloop join + * with the given append relation on the inside and the given outer_relids + * outside. Returns an AppendPath comprising the best inner scans, or + * NULL if there are no possible inner indexscans. */ -static void -join_before_append(PlannerInfo *root, - RelOptInfo *joinrel, - RelOptInfo *outerrel, - RelOptInfo *innerrel, - JoinType jointype) +static Path * +best_appendrel_indexscan(PlannerInfo *root, RelOptInfo *rel, + Relids outer_relids, JoinType jointype) { - Path *outer_cheapest_total = outerrel->cheapest_total_path; - int parentRTindex = innerrel->relid; + int parentRTindex = rel->relid; List *append_paths = NIL; + bool found_indexscan = false; ListCell *l; - /* - * Swapping JOIN with APPEND only works for inner joins, not outer joins. - * However, we can also handle a unique-ified outer path. - */ - switch (jointype) - { - case JOIN_INNER: - break; - case JOIN_UNIQUE_OUTER: - outer_cheapest_total = (Path *) - create_unique_path(root, outerrel, outer_cheapest_total); - break; - case JOIN_LEFT: - case JOIN_RIGHT: - case JOIN_FULL: - case JOIN_IN: - case JOIN_UNIQUE_INNER: - return; /* can't join this way */ - default: - elog(ERROR, "unrecognized join type: %d", - (int) jointype); - break; - } - - /* - * Generate suitable access paths for each member relation. - */ foreach(l, root->append_rel_list) { AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); int childRTindex; RelOptInfo *childrel; Path *bestinnerjoin; - RelOptInfo *this_joinrel; - List *this_restrictlist; /* append_rel_list contains all append rels; ignore others */ if (appinfo->parent_relid != parentRTindex) @@ -876,42 +829,30 @@ join_before_append(PlannerInfo *root, continue; /* OK, we can ignore it */ /* - * Get the best innerjoin indexpath (if any) for this outer rel. + * Get the best innerjoin indexpath (if any) for this child rel. */ bestinnerjoin = best_inner_indexscan(root, childrel, - outerrel->relids, JOIN_INNER); + outer_relids, jointype); + /* * If no luck on an indexpath for this rel, we'll still consider - * an Append substituting the cheapest-total inner path. This - * is only likely to win if there's at least one member rel for - * which an indexscan path does exist. + * an Append substituting the cheapest-total inner path. However + * we must find at least one indexpath, else there's not going to + * be any improvement over the base path for the appendrel. */ - if (!bestinnerjoin) + if (bestinnerjoin) + found_indexscan = true; + else bestinnerjoin = childrel->cheapest_total_path; - /* - * We need a joinrel that describes this join accurately. Although - * the joinrel won't ever be used by the join path search algorithm - * in joinrels.c, it provides necessary context for the Path, - * such as properly-translated target and quals lists. - */ - this_joinrel = translate_join_rel(root, joinrel, appinfo, - outerrel, childrel, jointype, - &this_restrictlist); - - /* Build Path for join and add to result list */ - append_paths = lappend(append_paths, - create_nestloop_path(root, - this_joinrel, - JOIN_INNER, - outer_cheapest_total, - bestinnerjoin, - this_restrictlist, - NIL)); + append_paths = lappend(append_paths, bestinnerjoin); } - /* Form the completed Append path and add it to the join relation. */ - add_path(joinrel, (Path *) create_append_path(joinrel, append_paths)); + if (!found_indexscan) + return NULL; + + /* Form and return the completed Append path. */ + return (Path *) create_append_path(rel, append_paths); } /* |
