summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/joinpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/joinpath.c')
-rw-r--r--src/backend/optimizer/path/joinpath.c137
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);
}
/*