aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/allpaths.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/allpaths.c')
-rw-r--r--src/backend/optimizer/path/allpaths.c192
1 files changed, 97 insertions, 95 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index c4d36a064b5..52c30f7d01d 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.57 2000/01/26 05:56:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.58 2000/02/07 04:40:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
+
#ifdef GEQO
bool enable_geqo = true;
#else
@@ -30,31 +31,28 @@ bool enable_geqo = false;
int geqo_rels = GEQO_RELS;
-static void set_base_rel_pathlist(Query *root, List *rels);
-static RelOptInfo *make_one_rel_by_joins(Query *root, List *rels,
- int levels_needed);
+static void set_base_rel_pathlist(Query *root);
+static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed);
#ifdef OPTIMIZER_DEBUG
static void debug_print_rel(Query *root, RelOptInfo *rel);
-
#endif
+
/*
* make_one_rel
* Finds all possible access paths for executing a query, returning a
- * single rel.
- *
- * 'rels' is the list of single relation entries appearing in the query
+ * single rel that represents the join of all base rels in the query.
*/
RelOptInfo *
-make_one_rel(Query *root, List *rels)
+make_one_rel(Query *root)
{
int levels_needed;
/*
* Set the number of join (not nesting) levels yet to be processed.
*/
- levels_needed = length(rels);
+ levels_needed = length(root->base_rel_list);
if (levels_needed <= 0)
return NULL;
@@ -62,159 +60,162 @@ make_one_rel(Query *root, List *rels)
/*
* Generate access paths for the base rels.
*/
- set_base_rel_pathlist(root, rels);
+ set_base_rel_pathlist(root);
- if (levels_needed <= 1)
+ if (levels_needed == 1)
{
/*
* Single relation, no more processing is required.
*/
- return lfirst(rels);
+ return (RelOptInfo *) lfirst(root->base_rel_list);
}
else
{
/*
* Generate join tree.
*/
- return make_one_rel_by_joins(root, rels, levels_needed);
+ return make_one_rel_by_joins(root, levels_needed);
}
}
/*
* set_base_rel_pathlist
- * Finds all paths available for scanning each relation entry in
- * 'rels'. Sequential scan and any available indices are considered
- * if possible (indices are not considered for lower nesting levels).
- * All useful paths are attached to the relation's 'pathlist' field.
- *
- * MODIFIES: rels
+ * Finds all paths available for scanning each base-relation entry.
+ * Sequential scan and any available indices are considered.
+ * Each useful path is attached to its relation's 'pathlist' field.
*/
static void
-set_base_rel_pathlist(Query *root, List *rels)
+set_base_rel_pathlist(Query *root)
{
- List *temp;
+ List *rellist;
- foreach(temp, rels)
+ foreach(rellist, root->base_rel_list)
{
- RelOptInfo *rel = (RelOptInfo *) lfirst(temp);
+ RelOptInfo *rel = (RelOptInfo *) lfirst(rellist);
List *indices = find_relation_indices(root, rel);
- List *sequential_scan_list;
- List *rel_index_scan_list;
- List *or_index_scan_list;
- List *tidscan_pathlist;
-
- sequential_scan_list = lcons(create_seqscan_path(rel), NIL);
- /* Tid Scan Pathlist add */
- tidscan_pathlist = create_tidscan_paths(root, rel);
- if (tidscan_pathlist)
- sequential_scan_list = nconc(sequential_scan_list,
- tidscan_pathlist);
- rel_index_scan_list = create_index_paths(root,
- rel,
- indices,
- rel->restrictinfo,
- rel->joininfo);
+
+ /* Mark rel with estimated output rows, width, etc */
+ set_baserel_size_estimates(root, rel);
+
+ /*
+ * Generate paths and add them to the rel's pathlist.
+ *
+ * add_path/add_pathlist will discard any paths that are dominated
+ * by another available path, keeping only those paths that are
+ * superior along at least one dimension of cost or sortedness.
+ */
+
+ /* Consider sequential scan */
+ add_path(rel, create_seqscan_path(rel));
+
+ /* Consider TID scans */
+ add_pathlist(rel, create_tidscan_paths(root, rel));
+
+ /* Consider index paths for both simple and OR index clauses */
+ add_pathlist(rel, create_index_paths(root,
+ rel,
+ indices,
+ rel->baserestrictinfo,
+ rel->joininfo));
/* Note: create_or_index_paths depends on create_index_paths
* to have marked OR restriction clauses with relevant indices;
* this is why it doesn't need to be given the full list of indices.
*/
- or_index_scan_list = create_or_index_paths(root, rel,
- rel->restrictinfo);
-
- /* add_pathlist will discard any paths that are dominated by
- * another available path, keeping only those paths that are
- * superior along at least one dimension of cost or sortedness.
- */
- rel->pathlist = add_pathlist(rel,
- sequential_scan_list,
- nconc(rel_index_scan_list,
- or_index_scan_list));
+ add_pathlist(rel, create_or_index_paths(root, rel,
+ rel->baserestrictinfo));
- /* Now find the cheapest of the paths */
+ /* Now find the cheapest of the paths for this rel */
set_cheapest(rel, rel->pathlist);
- /* Mark rel with estimated output rows and width */
- set_rel_rows_width(root, rel);
}
}
/*
* make_one_rel_by_joins
* Find all possible joinpaths for a query by successively finding ways
- * to join single relations into join relations.
- *
- * Find all possible joinpaths(bushy trees) for a query by systematically
- * finding ways to join relations(both original and derived) together.
+ * to join component relations into join relations.
*
- * 'rels' is the current list of relations for which join paths
- * are to be found, i.e., the current list of relations that
- * have already been derived.
- * 'levels_needed' is the number of iterations needed
+ * 'levels_needed' is the number of iterations needed, ie, the number of
+ * base relations present in the query
*
* Returns the final level of join relations, i.e., the relation that is
* the result of joining all the original relations together.
*/
static RelOptInfo *
-make_one_rel_by_joins(Query *root, List *rels, int levels_needed)
+make_one_rel_by_joins(Query *root, int levels_needed)
{
- List *x;
- List *joined_rels = NIL;
+ int lev;
RelOptInfo *rel;
/*******************************************
* genetic query optimizer entry point *
* <utesch@aut.tu-freiberg.de> *
+ * rest will be skipped in case of GEQO *
*******************************************/
- if (enable_geqo && length(root->base_rel_list) >= geqo_rels)
+ if (enable_geqo && levels_needed >= geqo_rels)
return geqo(root);
- /*******************************************
- * rest will be skipped in case of GEQO *
- *******************************************/
+ /*
+ * We employ a simple "dynamic programming" algorithm: we first
+ * find all ways to build joins of two base relations, then all ways
+ * to build joins of three base relations (from two-base-rel joins
+ * and other base rels), then four-base-rel joins, and so on until
+ * we have considered all ways to join all N relations into one rel.
+ */
- while (--levels_needed)
+ for (lev = 2; lev <= levels_needed; lev++)
{
+ List *first_old_rel = root->join_rel_list;
+ List *x;
/*
* Determine all possible pairs of relations to be joined at this
- * level. Determine paths for joining these relation pairs and
- * modify 'joined_rels' accordingly, then eliminate redundant join
- * relations.
+ * level, and build paths for making each one from every available
+ * pair of lower-level relations. Results are prepended to
+ * root->join_rel_list.
*/
- joined_rels = make_rels_by_joins(root, rels);
+ make_rels_by_joins(root, lev);
- update_rels_pathlist_for_joins(root, joined_rels);
-
- merge_rels_with_same_relids(joined_rels);
+ /*
+ * The relations created at the current level will appear at the
+ * front of root->join_rel_list.
+ */
+ foreach(x, root->join_rel_list)
+ {
+ if (x == first_old_rel)
+ break; /* no more rels added at this level */
- root->join_rel_list = rels = joined_rels;
+ rel = (RelOptInfo *) lfirst(x);
#ifdef NOT_USED
-
- /*
- * * for each expensive predicate in each path in each distinct
- * rel, * consider doing pullup -- JMH
- */
- if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
- foreach(x, joined_rels)
- xfunc_trypullup((RelOptInfo *) lfirst(x));
+ /*
+ * * for each expensive predicate in each path in each distinct
+ * rel, * consider doing pullup -- JMH
+ */
+ if (XfuncMode != XFUNC_NOPULL && XfuncMode != XFUNC_OFF)
+ xfunc_trypullup(rel);
#endif
- rels_set_cheapest(root, joined_rels);
-
- foreach(x, joined_rels)
- {
- rel = (RelOptInfo *) lfirst(x);
+ /* Find and save the cheapest path for this rel */
+ set_cheapest(rel, rel->pathlist);
#ifdef OPTIMIZER_DEBUG
- printf("levels left: %d\n", levels_needed);
debug_print_rel(root, rel);
#endif
}
-
}
- return get_cheapest_complete_rel(rels);
+ /*
+ * Now, the front of the join_rel_list should be the single rel
+ * representing the join of all the base rels.
+ */
+ Assert(length(root->join_rel_list) > 0);
+ rel = (RelOptInfo *) lfirst(root->join_rel_list);
+ Assert(length(rel->relids) == levels_needed);
+ Assert(length(root->join_rel_list) == 1 ||
+ length(((RelOptInfo *) lsecond(root->join_rel_list))->relids) < levels_needed);
+
+ return rel;
}
/*****************************************************************************
@@ -222,6 +223,7 @@ make_one_rel_by_joins(Query *root, List *rels, int levels_needed)
*****************************************************************************/
#ifdef OPTIMIZER_DEBUG
+
static void
print_joinclauses(Query *root, List *clauses)
{
@@ -286,7 +288,7 @@ print_path(Query *root, Path *path, int indent)
for (i = 0; i < indent + 1; i++)
printf("\t");
printf(" clauses=(");
- print_joinclauses(root, jp->path.parent->restrictinfo);
+ print_joinclauses(root, jp->joinrestrictinfo);
printf(")\n");
if (nodeTag(path) == T_MergePath)