aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/path/orindxpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/path/orindxpath.c')
-rw-r--r--src/backend/optimizer/path/orindxpath.c122
1 files changed, 66 insertions, 56 deletions
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index 9eb0484fc2f..6226100cfc7 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.36 2000/02/05 18:26:09 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.37 2000/02/15 20:49:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -19,6 +19,7 @@
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/internal.h"
+#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/plancat.h"
#include "optimizer/restrictinfo.h"
@@ -27,14 +28,13 @@
static void best_or_subclause_indices(Query *root, RelOptInfo *rel,
List *subclauses, List *indices,
- List **indexquals,
- List **indexids,
- Cost *cost);
+ IndexPath *pathnode);
static void best_or_subclause_index(Query *root, RelOptInfo *rel,
Expr *subclause, List *indices,
List **retIndexQual,
Oid *retIndexid,
- Cost *retCost);
+ Cost *retStartupCost,
+ Cost *retTotalCost);
/*
@@ -45,14 +45,13 @@ static void best_or_subclause_index(Query *root, RelOptInfo *rel,
* 'rel' is the relation entry for which the paths are to be created
* 'clauses' is the list of available restriction clause nodes
*
- * Returns a list of index path nodes.
- *
+ * Returns nothing, but adds paths to rel->pathlist via add_path().
*/
-List *
+void
create_or_index_paths(Query *root,
- RelOptInfo *rel, List *clauses)
+ RelOptInfo *rel,
+ List *clauses)
{
- List *path_list = NIL;
List *clist;
foreach(clist, clauses)
@@ -86,17 +85,6 @@ create_or_index_paths(Query *root,
* best available index for each subclause.
*/
IndexPath *pathnode = makeNode(IndexPath);
- List *indexquals;
- List *indexids;
- Cost cost;
-
- best_or_subclause_indices(root,
- rel,
- clausenode->clause->args,
- clausenode->subclauseindices,
- &indexquals,
- &indexids,
- &cost);
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel;
@@ -108,17 +96,21 @@ create_or_index_paths(Query *root,
*/
pathnode->path.pathkeys = NIL;
- pathnode->indexid = indexids;
- pathnode->indexqual = indexquals;
+ /* We don't actually care what order the index scans in ... */
+ pathnode->indexscandir = NoMovementScanDirection;
+
pathnode->joinrelids = NIL; /* no join clauses here */
- pathnode->path.path_cost = cost;
- path_list = lappend(path_list, pathnode);
+ best_or_subclause_indices(root,
+ rel,
+ clausenode->clause->args,
+ clausenode->subclauseindices,
+ pathnode);
+
+ add_path(rel, (Path *) pathnode);
}
}
}
-
- return path_list;
}
/*
@@ -128,53 +120,68 @@ create_or_index_paths(Query *root,
* indices. The cost is the sum of the individual index costs, since
* the executor will perform a scan for each subclause of the 'or'.
*
- * This routine also creates the indexquals and indexids lists that will
- * be needed by the executor. The indexquals list has one entry for each
+ * This routine also creates the indexqual and indexid lists that will
+ * be needed by the executor. The indexqual list has one entry for each
* scan of the base rel, which is a sublist of indexqual conditions to
* apply in that scan. The implicit semantics are AND across each sublist
* of quals, and OR across the toplevel list (note that the executor
- * takes care not to return any single tuple more than once). The indexids
- * list gives the index to be used in each scan.
+ * takes care not to return any single tuple more than once). The indexid
+ * list gives the OID of the index to be used in each scan.
*
* 'rel' is the node of the relation on which the indexes are defined
* 'subclauses' are the subclauses of the 'or' clause
* 'indices' is a list of sublists of the IndexOptInfo nodes that matched
* each subclause of the 'or' clause
- * '*indexquals' gets the constructed indexquals for the path (a list
+ * 'pathnode' is the IndexPath node being built.
+ *
+ * Results are returned by setting these fields of the passed pathnode:
+ * 'indexqual' gets the constructed indexquals for the path (a list
* of sublists of clauses, one sublist per scan of the base rel)
- * '*indexids' gets a list of the index OIDs for each scan of the rel
- * '*cost' gets the total cost of the path
+ * 'indexid' gets a list of the index OIDs for each scan of the rel
+ * 'startup_cost' and 'total_cost' get the complete path costs.
+ *
+ * 'startup_cost' is the startup cost for the first index scan only;
+ * startup costs for later scans will be paid later on, so they just
+ * get reflected in total_cost.
+ *
+ * NOTE: we choose each scan on the basis of its total cost, ignoring startup
+ * cost. This is reasonable as long as all index types have zero or small
+ * startup cost, but we might have to work harder if any index types with
+ * nontrivial startup cost are ever invented.
*/
static void
best_or_subclause_indices(Query *root,
RelOptInfo *rel,
List *subclauses,
List *indices,
- List **indexquals, /* return value */
- List **indexids, /* return value */
- Cost *cost) /* return value */
+ IndexPath *pathnode)
{
List *slist;
- *indexquals = NIL;
- *indexids = NIL;
- *cost = (Cost) 0.0;
+ pathnode->indexqual = NIL;
+ pathnode->indexid = NIL;
+ pathnode->path.startup_cost = 0;
+ pathnode->path.total_cost = 0;
foreach(slist, subclauses)
{
Expr *subclause = lfirst(slist);
List *best_indexqual;
Oid best_indexid;
- Cost best_cost;
+ Cost best_startup_cost;
+ Cost best_total_cost;
best_or_subclause_index(root, rel, subclause, lfirst(indices),
- &best_indexqual, &best_indexid, &best_cost);
+ &best_indexqual, &best_indexid,
+ &best_startup_cost, &best_total_cost);
Assert(best_indexid != InvalidOid);
- *indexquals = lappend(*indexquals, best_indexqual);
- *indexids = lappendi(*indexids, best_indexid);
- *cost += best_cost;
+ pathnode->indexqual = lappend(pathnode->indexqual, best_indexqual);
+ pathnode->indexid = lappendi(pathnode->indexid, best_indexid);
+ if (slist == subclauses) /* first scan? */
+ pathnode->path.startup_cost = best_startup_cost;
+ pathnode->path.total_cost += best_total_cost;
indices = lnext(indices);
}
@@ -182,16 +189,17 @@ best_or_subclause_indices(Query *root,
/*
* best_or_subclause_index
- * Determines which is the best index to be used with a subclause of
- * an 'or' clause by estimating the cost of using each index and selecting
- * the least expensive.
+ * Determines which is the best index to be used with a subclause of an
+ * 'or' clause by estimating the cost of using each index and selecting
+ * the least expensive (considering total cost only, for now).
*
* 'rel' is the node of the relation on which the index is defined
* 'subclause' is the OR subclause being considered
* 'indices' is a list of IndexOptInfo nodes that match the subclause
* '*retIndexQual' gets a list of the indexqual conditions for the best index
* '*retIndexid' gets the OID of the best index
- * '*retCost' gets the cost of a scan with that index
+ * '*retStartupCost' gets the startup cost of a scan with that index
+ * '*retTotalCost' gets the total cost of a scan with that index
*/
static void
best_or_subclause_index(Query *root,
@@ -200,7 +208,8 @@ best_or_subclause_index(Query *root,
List *indices,
List **retIndexQual, /* return value */
Oid *retIndexid, /* return value */
- Cost *retCost) /* return value */
+ Cost *retStartupCost, /* return value */
+ Cost *retTotalCost) /* return value */
{
bool first_time = true;
List *ilist;
@@ -208,27 +217,28 @@ best_or_subclause_index(Query *root,
/* if we don't match anything, return zeros */
*retIndexQual = NIL;
*retIndexid = InvalidOid;
- *retCost = 0.0;
+ *retStartupCost = 0;
+ *retTotalCost = 0;
foreach(ilist, indices)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
List *indexqual;
- Cost subcost;
+ Path subclause_path;
Assert(IsA(index, IndexOptInfo));
/* Convert this 'or' subclause to an indexqual list */
indexqual = extract_or_indexqual_conditions(rel, index, subclause);
- subcost = cost_index(root, rel, index, indexqual,
- false);
+ cost_index(&subclause_path, root, rel, index, indexqual, false);
- if (first_time || subcost < *retCost)
+ if (first_time || subclause_path.total_cost < *retTotalCost)
{
*retIndexQual = indexqual;
*retIndexid = index->indexoid;
- *retCost = subcost;
+ *retStartupCost = subclause_path.startup_cost;
+ *retTotalCost = subclause_path.total_cost;
first_time = false;
}
}