aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/access/index/indexam.c38
-rw-r--r--src/backend/commands/variable.c51
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/readfuncs.c32
-rw-r--r--src/backend/optimizer/path/_deadcode/xfunc.c14
-rw-r--r--src/backend/optimizer/path/allpaths.c15
-rw-r--r--src/backend/optimizer/path/costsize.c147
-rw-r--r--src/backend/optimizer/path/indxpath.c22
-rw-r--r--src/backend/optimizer/path/joinpath.c6
-rw-r--r--src/backend/optimizer/path/orindxpath.c14
-rw-r--r--src/backend/optimizer/plan/initsplan.c6
-rw-r--r--src/backend/optimizer/util/pathnode.c60
-rw-r--r--src/backend/optimizer/util/plancat.c213
-rw-r--r--src/backend/tcop/postgres.c17
-rw-r--r--src/backend/utils/adt/selfuncs.c390
15 files changed, 234 insertions, 794 deletions
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index dc08d10bc31..3c286f6ec74 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.38 1999/12/30 05:04:50 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.39 2000/01/22 23:50:09 tgl Exp $
*
* INTERFACE ROUTINES
* index_open - open an index relation by relationId
@@ -69,21 +69,6 @@
#include "access/heapam.h"
#include "utils/relcache.h"
-/* ----------------
- * undefine macros we aren't going to use that would otherwise
- * get in our way.. delete is defined in c.h and the am's are
- * defined in heapam.h
- * ----------------
- */
-#undef delete
-#undef aminsert
-#undef amdelete
-#undef ambeginscan
-#undef amrescan
-#undef amendscan
-#undef ammarkpos
-#undef amrestrpos
-#undef amgettuple
/* ----------------------------------------------------------------
* macros used in index_ routines
@@ -359,6 +344,27 @@ index_getnext(IndexScanDesc scan,
}
/* ----------------
+ * index_cost_estimator
+ *
+ * Fetch the amcostestimate procedure OID for an index.
+ *
+ * We could combine fetching and calling the procedure,
+ * as index_insert does for example; but that would require
+ * importing a bunch of planner/optimizer stuff into this file.
+ * ----------------
+ */
+RegProcedure
+index_cost_estimator(Relation relation)
+{
+ RegProcedure procedure;
+
+ RELATION_CHECKS;
+ GET_REL_PROCEDURE(cost_estimator, amcostestimate);
+
+ return procedure;
+}
+
+/* ----------------
* index_getprocid
*
* Some indexed access methods may require support routines that are
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 031512839c2..52c4ed3552a 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -2,7 +2,7 @@
* Routines for handling of 'SET var TO',
* 'SHOW var' and 'RESET var' statements.
*
- * $Id: variable.c,v 1.27 2000/01/15 02:59:29 petere Exp $
+ * $Id: variable.c,v 1.28 2000/01/22 23:50:10 tgl Exp $
*
*/
@@ -14,7 +14,8 @@
#include "catalog/pg_shadow.h"
#include "commands/variable.h"
#include "miscadmin.h"
-#include "optimizer/internal.h"
+#include "optimizer/cost.h"
+#include "optimizer/paths.h"
#include "utils/builtins.h"
#include "utils/tqual.h"
#include "utils/trace.h"
@@ -45,10 +46,6 @@ static bool show_XactIsoLevel(void);
static bool reset_XactIsoLevel(void);
static bool parse_XactIsoLevel(const char *);
-extern Cost _cpu_page_weight_;
-extern Cost _cpu_index_page_weight_;
-extern bool _use_geqo_;
-extern int32 _use_geqo_rels_;
extern bool _use_keyset_query_optimizer;
/*
@@ -183,23 +180,23 @@ parse_geqo(const char *value)
if (strcasecmp(tok, "on") == 0)
{
- int32 geqo_rels = GEQO_RELS;
+ int new_geqo_rels = GEQO_RELS;
if (val != NULL)
{
- geqo_rels = pg_atoi(val, sizeof(int32), '\0');
- if (geqo_rels <= 1)
+ new_geqo_rels = pg_atoi(val, sizeof(int), '\0');
+ if (new_geqo_rels <= 1)
elog(ERROR, "Bad value for # of relations (%s)", val);
pfree(val);
}
- _use_geqo_ = true;
- _use_geqo_rels_ = geqo_rels;
+ enable_geqo = true;
+ geqo_rels = new_geqo_rels;
}
else if (strcasecmp(tok, "off") == 0)
{
if ((val != NULL) && (*val != '\0'))
elog(ERROR, "%s does not allow a parameter", tok);
- _use_geqo_ = false;
+ enable_geqo = false;
}
else
elog(ERROR, "Bad value for GEQO (%s)", value);
@@ -212,8 +209,8 @@ static bool
show_geqo()
{
- if (_use_geqo_)
- elog(NOTICE, "GEQO is ON beginning with %d relations", _use_geqo_rels_);
+ if (enable_geqo)
+ elog(NOTICE, "GEQO is ON beginning with %d relations", geqo_rels);
else
elog(NOTICE, "GEQO is OFF");
return TRUE;
@@ -224,11 +221,11 @@ reset_geqo(void)
{
#ifdef GEQO
- _use_geqo_ = true;
+ enable_geqo = true;
#else
- _use_geqo_ = false;
+ enable_geqo = false;
#endif
- _use_geqo_rels_ = GEQO_RELS;
+ geqo_rels = GEQO_RELS;
return TRUE;
}
@@ -240,7 +237,7 @@ reset_geqo(void)
static bool
parse_cost_heap(const char *value)
{
- float32 res;
+ float64 res;
if (value == NULL)
{
@@ -248,8 +245,8 @@ parse_cost_heap(const char *value)
return TRUE;
}
- res = float4in((char *) value);
- _cpu_page_weight_ = *res;
+ res = float8in((char *) value);
+ cpu_page_weight = *res;
return TRUE;
}
@@ -258,14 +255,14 @@ static bool
show_cost_heap()
{
- elog(NOTICE, "COST_HEAP is %f", _cpu_page_weight_);
+ elog(NOTICE, "COST_HEAP is %f", cpu_page_weight);
return TRUE;
}
static bool
reset_cost_heap()
{
- _cpu_page_weight_ = _CPU_PAGE_WEIGHT_;
+ cpu_page_weight = CPU_PAGE_WEIGHT;
return TRUE;
}
@@ -277,7 +274,7 @@ reset_cost_heap()
static bool
parse_cost_index(const char *value)
{
- float32 res;
+ float64 res;
if (value == NULL)
{
@@ -285,8 +282,8 @@ parse_cost_index(const char *value)
return TRUE;
}
- res = float4in((char *) value);
- _cpu_index_page_weight_ = *res;
+ res = float8in((char *) value);
+ cpu_index_page_weight = *res;
return TRUE;
}
@@ -295,14 +292,14 @@ static bool
show_cost_index()
{
- elog(NOTICE, "COST_INDEX is %f", _cpu_index_page_weight_);
+ elog(NOTICE, "COST_INDEX is %f", cpu_index_page_weight);
return TRUE;
}
static bool
reset_cost_index()
{
- _cpu_index_page_weight_ = _CPU_INDEX_PAGE_WEIGHT_;
+ cpu_index_page_weight = CPU_INDEX_PAGE_WEIGHT;
return TRUE;
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 241b8ca1035..5cbea551659 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.100 2000/01/17 00:14:46 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.101 2000/01/22 23:50:11 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1031,6 +1031,7 @@ _copyIndexOptInfo(IndexOptInfo *from)
}
newnode->relam = from->relam;
+ newnode->amcostestimate = from->amcostestimate;
newnode->indproc = from->indproc;
Node_Copy(from, newnode, indpred);
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 9c1219b7860..8e6f68bdfd7 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.78 2000/01/14 00:53:21 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.79 2000/01/22 23:50:12 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
@@ -1331,34 +1331,6 @@ _readRelOptInfo()
}
/* ----------------
- * _readIndexOptInfo
- * ----------------
- */
-static IndexOptInfo *
-_readIndexOptInfo()
-{
- IndexOptInfo *local_node;
- char *token;
- int length;
-
- local_node = makeNode(IndexOptInfo);
-
- token = lsptok(NULL, &length); /* get :indexoid */
- token = lsptok(NULL, &length); /* now read it */
- local_node->indexoid = (Oid) atoi(token);
-
- token = lsptok(NULL, &length); /* get :pages */
- token = lsptok(NULL, &length); /* now read it */
- local_node->pages = atol(token);
-
- token = lsptok(NULL, &length); /* get :tuples */
- token = lsptok(NULL, &length); /* now read it */
- local_node->tuples = atof(token);
-
- return local_node;
-}
-
-/* ----------------
* _readTargetEntry
* ----------------
*/
@@ -1900,8 +1872,6 @@ parsePlanString(void)
return_value = _readEState();
else if (length == 10 && strncmp(token, "RELOPTINFO", length) == 0)
return_value = _readRelOptInfo();
- else if (length == 12 && strncmp(token, "INDEXOPTINFO", length) == 0)
- return_value = _readIndexOptInfo();
else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
return_value = _readTargetEntry();
else if (length == 3 && strncmp(token, "RTE", length) == 0)
diff --git a/src/backend/optimizer/path/_deadcode/xfunc.c b/src/backend/optimizer/path/_deadcode/xfunc.c
index 771cec3ecd9..82c26cee5f9 100644
--- a/src/backend/optimizer/path/_deadcode/xfunc.c
+++ b/src/backend/optimizer/path/_deadcode/xfunc.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/_deadcode/Attic/xfunc.c,v 1.11 1999/11/22 17:56:10 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/_deadcode/Attic/xfunc.c,v 1.12 2000/01/22 23:50:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1100,27 +1100,27 @@ xfunc_expense_per_tuple(JoinPath joinnode, int whichchild)
if (IsA(joinnode, HashPath))
{
if (whichchild == INNER)
- return (1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers;
+ return (1 + cpu_page_weight) * outers_per_page / NBuffers;
else
- return (((1 + _CPU_PAGE_WEIGHT_) * outers_per_page / NBuffers)
- + _CPU_PAGE_WEIGHT_
+ return (((1 + cpu_page_weight) * outers_per_page / NBuffers)
+ + cpu_page_weight
/ xfunc_card_product(get_relids(innerrel)));
}
else if (IsA(joinnode, MergePath))
{
/* assumes sort exists, and costs one (I/O + CPU) per tuple */
if (whichchild == INNER)
- return ((2 * _CPU_PAGE_WEIGHT_ + 1)
+ return ((2 * cpu_page_weight + 1)
/ xfunc_card_product(get_relids(outerrel)));
else
- return ((2 * _CPU_PAGE_WEIGHT_ + 1)
+ return ((2 * cpu_page_weight + 1)
/ xfunc_card_product(get_relids(innerrel)));
}
else
/* nestloop */
{
Assert(IsA(joinnode, JoinPath));
- return _CPU_PAGE_WEIGHT_;
+ return cpu_page_weight;
}
}
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 1e357d4b8fd..5cae7651eec 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.55 2000/01/09 00:26:29 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.56 2000/01/22 23:50:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,13 +21,12 @@
#include "optimizer/paths.h"
#ifdef GEQO
-bool _use_geqo_ = true;
-
+bool enable_geqo = true;
#else
-bool _use_geqo_ = false;
-
+bool enable_geqo = false;
#endif
-int32 _use_geqo_rels_ = GEQO_RELS;
+
+int geqo_rels = GEQO_RELS;
static void set_base_rel_pathlist(Query *root, List *rels);
@@ -165,11 +164,11 @@ make_one_rel_by_joins(Query *root, List *rels, int levels_needed)
* genetic query optimizer entry point *
* <utesch@aut.tu-freiberg.de> *
*******************************************/
- if ((_use_geqo_) && length(root->base_rel_list) >= _use_geqo_rels_)
+ if (enable_geqo && length(root->base_rel_list) >= geqo_rels)
return geqo(root);
/*******************************************
- * rest will be deprecated in case of GEQO *
+ * rest will be skipped in case of GEQO *
*******************************************/
while (--levels_needed)
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 8261e17c02e..5c0f54a73e2 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -5,20 +5,20 @@
*
* Path costs are measured in units of disk accesses: one page fetch
* has cost 1. The other primitive unit is the CPU time required to
- * process one tuple, which we set at "_cpu_page_weight_" of a page
+ * process one tuple, which we set at "cpu_page_weight" of a page
* fetch. Obviously, the CPU time per tuple depends on the query
* involved, but the relative CPU and disk speeds of a given platform
* are so variable that we are lucky if we can get useful numbers
- * at all. _cpu_page_weight_ is user-settable, in case a particular
+ * at all. cpu_page_weight is user-settable, in case a particular
* user is clueful enough to have a better-than-default estimate
- * of the ratio for his platform. There is also _cpu_index_page_weight_,
+ * of the ratio for his platform. There is also cpu_index_page_weight,
* the cost to process a tuple of an index during an index scan.
*
*
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.47 2000/01/09 00:26:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.48 2000/01/22 23:50:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -44,6 +44,20 @@
#include "utils/lsyscache.h"
+Cost cpu_page_weight = CPU_PAGE_WEIGHT;
+Cost cpu_index_page_weight = CPU_INDEX_PAGE_WEIGHT;
+
+Cost disable_cost = 100000000.0;
+
+bool enable_seqscan = true;
+bool enable_indexscan = true;
+bool enable_tidscan = true;
+bool enable_sort = true;
+bool enable_nestloop = true;
+bool enable_mergejoin = true;
+bool enable_hashjoin = true;
+
+
static void set_rel_width(Query *root, RelOptInfo *rel);
static int compute_attribute_width(TargetEntry *tlistentry);
static double relation_byte_size(double tuples, int width);
@@ -51,19 +65,6 @@ static double page_size(double tuples, int width);
static double base_log(double x, double b);
-Cost _cpu_page_weight_ = _CPU_PAGE_WEIGHT_;
-Cost _cpu_index_page_weight_ = _CPU_INDEX_PAGE_WEIGHT_;
-
-Cost _disable_cost_ = 100000000.0;
-
-bool _enable_seqscan_ = true;
-bool _enable_indexscan_ = true;
-bool _enable_sort_ = true;
-bool _enable_nestloop_ = true;
-bool _enable_mergejoin_ = true;
-bool _enable_hashjoin_ = true;
-bool _enable_tidscan_ = true;
-
/*
* cost_seqscan
* Determines and returns the cost of scanning a relation sequentially.
@@ -84,8 +85,8 @@ cost_seqscan(RelOptInfo *baserel)
/* Should only be applied to base relations */
Assert(length(baserel->relids) == 1);
- if (!_enable_seqscan_)
- temp += _disable_cost_;
+ if (!enable_seqscan)
+ temp += disable_cost;
if (lfirsti(baserel->relids) < 0)
{
@@ -97,7 +98,7 @@ cost_seqscan(RelOptInfo *baserel)
else
{
temp += baserel->pages;
- temp += _cpu_page_weight_ * baserel->tuples;
+ temp += cpu_page_weight * baserel->tuples;
}
Assert(temp >= 0);
@@ -109,58 +110,54 @@ cost_seqscan(RelOptInfo *baserel)
* cost_index
* Determines and returns the cost of scanning a relation using an index.
*
- * disk = expected-index-pages + expected-data-pages
- * cpu = CPU-INDEX-PAGE-WEIGHT * expected-index-tuples +
- * CPU-PAGE-WEIGHT * expected-data-tuples
+ * NOTE: an indexscan plan node can actually represent several passes,
+ * but here we consider the cost of just one pass.
*
+ * 'root' is the query root
* 'baserel' is the base relation the index is for
* 'index' is the index to be used
- * 'expected_indexpages' is the estimated number of index pages that will
- * be touched in the scan (this is computed by index-type-specific code)
- * 'selec' is the selectivity of the index, ie, the fraction of base-relation
- * tuples that we will have to fetch and examine
+ * 'indexQuals' is the list of applicable qual clauses (implicit AND semantics)
* 'is_injoin' is T if we are considering using the index scan as the inside
* of a nestloop join.
*
- * NOTE: 'selec' should be calculated on the basis of indexqual conditions
- * only. Any additional quals evaluated as qpquals may reduce the number
- * of returned tuples, but they won't reduce the number of tuples we have
- * to fetch from the table, so they don't reduce the scan cost.
+ * NOTE: 'indexQuals' must contain only clauses usable as index restrictions.
+ * Any additional quals evaluated as qpquals may reduce the number of returned
+ * tuples, but they won't reduce the number of tuples we have to fetch from
+ * the table, so they don't reduce the scan cost.
*/
Cost
-cost_index(RelOptInfo *baserel,
+cost_index(Query *root,
+ RelOptInfo *baserel,
IndexOptInfo *index,
- long expected_indexpages,
- Selectivity selec,
+ List *indexQuals,
bool is_injoin)
{
Cost temp = 0;
- double reltuples = selec * baserel->tuples;
- double indextuples = selec * index->tuples;
+ Cost indexAccessCost;
+ Selectivity indexSelectivity;
+ double reltuples;
double relpages;
/* Should only be applied to base relations */
Assert(IsA(baserel, RelOptInfo) && IsA(index, IndexOptInfo));
Assert(length(baserel->relids) == 1);
- if (!_enable_indexscan_ && !is_injoin)
- temp += _disable_cost_;
+ if (!enable_indexscan && !is_injoin)
+ temp += disable_cost;
/*
- * We want to be sure we estimate the cost of an index scan as more
- * than the cost of a sequential scan (when selec == 1.0), even if we
- * don't have good stats. So, disbelieve zero index size.
+ * Call index-access-method-specific code to estimate the processing
+ * cost for scanning the index, as well as the selectivity of the index
+ * (ie, the fraction of main-table tuples we will have to retrieve).
*/
- if (expected_indexpages <= 0)
- expected_indexpages = 1;
- if (indextuples <= 0.0)
- indextuples = 1.0;
+ fmgr(index->amcostestimate, root, baserel, index, indexQuals,
+ &indexAccessCost, &indexSelectivity);
- /* expected index relation pages */
- temp += expected_indexpages;
+ /* all costs for touching index itself included here */
+ temp += indexAccessCost;
/*--------------------
- * expected base relation pages
+ * Estimate number of main-table tuples and pages touched.
*
* Worst case is that each tuple the index tells us to fetch comes
* from a different base-rel page, in which case the I/O cost would be
@@ -178,6 +175,8 @@ cost_index(RelOptInfo *baserel,
* So, we guess-and-hope that these sources of error will more or less
* balance out.
*
+ * XXX need to add a penalty for nonsequential page fetches.
+ *
* XXX if the relation has recently been "clustered" using this index,
* then in fact the target tuples will be highly nonuniformly distributed,
* and we will be seriously overestimating the scan cost! Currently we
@@ -186,16 +185,18 @@ cost_index(RelOptInfo *baserel,
* effect. Would be nice to do better someday.
*--------------------
*/
+
+ reltuples = indexSelectivity * baserel->tuples;
+
relpages = reltuples;
if (baserel->pages > 0 && baserel->pages < relpages)
relpages = baserel->pages;
- temp += relpages;
- /* per index tuples */
- temp += _cpu_index_page_weight_ * indextuples;
+ /* disk costs for main table */
+ temp += relpages;
- /* per heap tuples */
- temp += _cpu_page_weight_ * reltuples;
+ /* CPU costs for heap tuples */
+ temp += cpu_page_weight * reltuples;
Assert(temp >= 0);
return temp;
@@ -213,10 +214,10 @@ cost_tidscan(RelOptInfo *baserel, List *tideval)
{
Cost temp = 0;
- if (!_enable_tidscan_)
- temp += _disable_cost_;
+ if (!enable_tidscan)
+ temp += disable_cost;
- temp += (1.0 + _cpu_page_weight_) * length(tideval);
+ temp += (1.0 + cpu_page_weight) * length(tideval);
return temp;
}
@@ -227,7 +228,7 @@ cost_tidscan(RelOptInfo *baserel, List *tideval)
*
* If the total volume of data to sort is less than SortMem, we will do
* an in-memory sort, which requires no I/O and about t*log2(t) tuple
- * comparisons for t tuples. We use _cpu_index_page_weight as the cost
+ * comparisons for t tuples. We use cpu_index_page_weight as the cost
* of a tuple comparison (is this reasonable, or do we need another
* basic parameter?).
*
@@ -257,8 +258,8 @@ cost_sort(List *pathkeys, double tuples, int width)
double nbytes = relation_byte_size(tuples, width);
long sortmembytes = SortMem * 1024L;
- if (!_enable_sort_)
- temp += _disable_cost_;
+ if (!enable_sort)
+ temp += disable_cost;
/*
* We want to be sure the cost of a sort is never estimated as zero,
@@ -268,7 +269,7 @@ cost_sort(List *pathkeys, double tuples, int width)
if (tuples < 2.0)
tuples = 2.0;
- temp += _cpu_index_page_weight_ * tuples * base_log(tuples, 2.0);
+ temp += cpu_index_page_weight * tuples * base_log(tuples, 2.0);
if (nbytes > sortmembytes)
{
@@ -298,7 +299,7 @@ cost_result(double tuples, int width)
Cost temp = 0;
temp += page_size(tuples, width);
- temp += _cpu_page_weight_ * tuples;
+ temp += cpu_page_weight * tuples;
Assert(temp >= 0);
return temp;
}
@@ -321,8 +322,8 @@ cost_nestloop(Path *outer_path,
{
Cost temp = 0;
- if (!_enable_nestloop_)
- temp += _disable_cost_;
+ if (!enable_nestloop)
+ temp += disable_cost;
temp += outer_path->path_cost;
temp += outer_path->parent->rows * inner_path->path_cost;
@@ -350,8 +351,8 @@ cost_mergejoin(Path *outer_path,
{
Cost temp = 0;
- if (!_enable_mergejoin_)
- temp += _disable_cost_;
+ if (!enable_mergejoin)
+ temp += disable_cost;
/* cost of source data */
temp += outer_path->path_cost + inner_path->path_cost;
@@ -372,8 +373,8 @@ cost_mergejoin(Path *outer_path,
* underestimate if there are many equal-keyed tuples in either relation,
* but we have no good way of estimating that...
*/
- temp += _cpu_page_weight_ * (outer_path->parent->rows +
- inner_path->parent->rows);
+ temp += cpu_page_weight * (outer_path->parent->rows +
+ inner_path->parent->rows);
Assert(temp >= 0);
return temp;
@@ -401,23 +402,23 @@ cost_hashjoin(Path *outer_path,
inner_path->parent->width);
long hashtablebytes = SortMem * 1024L;
- if (!_enable_hashjoin_)
- temp += _disable_cost_;
+ if (!enable_hashjoin)
+ temp += disable_cost;
/* cost of source data */
temp += outer_path->path_cost + inner_path->path_cost;
/* cost of computing hash function: must do it once per tuple */
- temp += _cpu_page_weight_ * (outer_path->parent->rows +
- inner_path->parent->rows);
+ temp += cpu_page_weight * (outer_path->parent->rows +
+ inner_path->parent->rows);
/* the number of tuple comparisons needed is the number of outer
* tuples times the typical hash bucket size, which we estimate
* conservatively as the inner disbursion times the inner tuple
- * count. The cost per comparison is set at _cpu_index_page_weight_;
+ * count. The cost per comparison is set at cpu_index_page_weight;
* is that reasonable, or do we need another basic parameter?
*/
- temp += _cpu_index_page_weight_ * outer_path->parent->rows *
+ temp += cpu_index_page_weight * outer_path->parent->rows *
(inner_path->parent->rows * innerdisbursion);
/*
diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c
index 3c93ee67ac3..7bb4a8eaeb1 100644
--- a/src/backend/optimizer/path/indxpath.c
+++ b/src/backend/optimizer/path/indxpath.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.76 2000/01/09 00:26:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.77 2000/01/22 23:50:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1393,19 +1393,6 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
List *clausegroup = lfirst(i);
IndexPath *pathnode = makeNode(IndexPath);
List *indexquals;
- long npages;
- Selectivity selec;
-
- indexquals = get_actual_clauses(clausegroup);
- /* expand special operators to indexquals the executor can handle */
- indexquals = expand_indexqual_conditions(indexquals);
-
- index_selectivity(root,
- rel,
- index,
- indexquals,
- &npages,
- &selec);
/* XXX this code ought to be merged with create_index_path? */
@@ -1413,6 +1400,10 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
pathnode->path.parent = rel;
pathnode->path.pathkeys = build_index_pathkeys(root, rel, index);
+ indexquals = get_actual_clauses(clausegroup);
+ /* expand special operators to indexquals the executor can handle */
+ indexquals = expand_indexqual_conditions(indexquals);
+
/* Note that we are making a pathnode for a single-scan indexscan;
* therefore, both indexid and indexqual should be single-element
* lists.
@@ -1423,8 +1414,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
/* joinrelids saves the rels needed on the outer side of the join */
pathnode->joinrelids = lfirst(outerrelids_list);
- pathnode->path.path_cost = cost_index(rel, index,
- npages, selec,
+ pathnode->path.path_cost = cost_index(root, rel, index, indexquals,
true);
path_list = lappend(path_list, pathnode);
diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c
index 5c7df62fa20..f29a5cc8163 100644
--- a/src/backend/optimizer/path/joinpath.c
+++ b/src/backend/optimizer/path/joinpath.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.47 2000/01/09 00:26:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.48 2000/01/22 23:50:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -102,7 +102,7 @@ update_rels_pathlist_for_joins(Query *root, List *joinrels)
/*
* Find potential mergejoin clauses.
*/
- if (_enable_mergejoin_)
+ if (enable_mergejoin)
mergeclause_list = select_mergejoin_clauses(joinrel->restrictinfo);
/*
@@ -141,7 +141,7 @@ update_rels_pathlist_for_joins(Query *root, List *joinrels)
* 4. Consider paths where both outer and inner relations must be
* hashed before being joined.
*/
- if (_enable_hashjoin_)
+ if (enable_hashjoin)
pathlist = add_pathlist(joinrel, pathlist,
hash_inner_and_outer(root, joinrel,
outerrel,
diff --git a/src/backend/optimizer/path/orindxpath.c b/src/backend/optimizer/path/orindxpath.c
index f5813a27a8e..2831342fd88 100644
--- a/src/backend/optimizer/path/orindxpath.c
+++ b/src/backend/optimizer/path/orindxpath.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.33 2000/01/09 00:26:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.34 2000/01/22 23:50:15 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -215,21 +215,11 @@ best_or_subclause_index(Query *root,
foreach(ilist, indices)
{
IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
- long npages;
- Selectivity selec;
Cost subcost;
Assert(IsA(index, IndexOptInfo));
- index_selectivity(root,
- rel,
- index,
- indexqual,
- &npages,
- &selec);
-
- subcost = cost_index(rel, index,
- npages, selec,
+ subcost = cost_index(root, rel, index, indexqual,
false);
if (first_run || subcost < *retCost)
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 7316a794612..87d321feff7 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.41 2000/01/09 00:26:36 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.42 2000/01/22 23:50:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -257,9 +257,9 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
static void
set_restrictinfo_joininfo(RestrictInfo *restrictinfo)
{
- if (_enable_mergejoin_)
+ if (enable_mergejoin)
check_mergejoinable(restrictinfo);
- if (_enable_hashjoin_)
+ if (enable_hashjoin)
check_hashjoinable(restrictinfo);
}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index a2551391e00..5c093acc9f5 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.56 2000/01/09 00:26:37 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.57 2000/01/22 23:50:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -214,64 +214,26 @@ create_index_path(Query *root,
List *restriction_clauses)
{
IndexPath *pathnode = makeNode(IndexPath);
+ List *indexquals;
pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel;
pathnode->path.pathkeys = build_index_pathkeys(root, rel, index);
+ indexquals = get_actual_clauses(restriction_clauses);
+ /* expand special operators to indexquals the executor can handle */
+ indexquals = expand_indexqual_conditions(indexquals);
+
/*
- * Note that we are making a pathnode for a single-scan indexscan;
- * therefore, both indexid and indexqual should be single-element
- * lists. We initialize indexqual to contain one empty sublist,
- * representing a single index traversal with no index restriction
- * conditions. If we do have restriction conditions to use, they
- * will get inserted below.
+ * We are making a pathnode for a single-scan indexscan; therefore,
+ * both indexid and indexqual should be single-element lists.
*/
pathnode->indexid = lconsi(index->indexoid, NIL);
- pathnode->indexqual = lcons(NIL, NIL);
+ pathnode->indexqual = lcons(indexquals, NIL);
pathnode->joinrelids = NIL; /* no join clauses here */
- if (restriction_clauses == NIL)
- {
- /*
- * We have no restriction clauses, so compute scan cost using
- * selectivity of 1.0.
- */
- pathnode->path.path_cost = cost_index(rel, index,
- index->pages,
- (Selectivity) 1.0,
- false);
- }
- else
- {
- /*
- * Compute scan cost for the case when 'index' is used with
- * restriction clause(s). Also, place indexqual in path node.
- */
- List *indexquals;
- long npages;
- Selectivity selec;
-
- indexquals = get_actual_clauses(restriction_clauses);
- /* expand special operators to indexquals the executor can handle */
- indexquals = expand_indexqual_conditions(indexquals);
-
- /* Insert qual list into 1st sublist of pathnode->indexqual;
- * we already made the cons cell above, no point in wasting it...
- */
- lfirst(pathnode->indexqual) = indexquals;
-
- index_selectivity(root,
- rel,
- index,
- indexquals,
- &npages,
- &selec);
-
- pathnode->path.path_cost = cost_index(rel, index,
- npages, selec,
- false);
- }
+ pathnode->path.path_cost = cost_index(root, rel, index, indexquals,
+ false);
return pathnode;
}
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 6468ef528fd..4c191f02b55 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.44 2000/01/15 02:59:31 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.45 2000/01/22 23:50:17 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -136,6 +136,7 @@ find_secondary_indexes(Query *root, Index relid)
info->relam = relam;
info->pages = indexRelation->rd_rel->relpages;
info->tuples = indexRelation->rd_rel->reltuples;
+ info->amcostestimate = index_cost_estimator(indexRelation);
index_close(indexRelation);
/*
@@ -169,216 +170,6 @@ find_secondary_indexes(Query *root, Index relid)
}
/*
- * index_selectivity
- * Estimate the selectivity of an index scan with the given index quals.
- *
- * NOTE: an indexscan plan node can actually represent several passes,
- * but here we consider the cost of just one pass.
- *
- * 'root' is the query root
- * 'rel' is the relation being scanned
- * 'index' is the index to be used
- * 'indexquals' is the list of qual condition exprs (implicit AND semantics)
- * '*idxPages' receives an estimate of the number of index pages touched
- * '*idxSelec' receives an estimate of selectivity of the scan, ie fraction
- * of the relation's tuples that will be retrieved
- */
-void
-index_selectivity(Query *root,
- RelOptInfo *rel,
- IndexOptInfo *index,
- List *indexquals,
- long *idxPages,
- Selectivity *idxSelec)
-{
- int relid;
- Oid baserelid,
- indexrelid;
- HeapTuple indRel,
- indexTuple;
- Form_pg_class indexrelation;
- Oid relam;
- Form_pg_index pgindex;
- int nIndexKeys;
- float64data npages,
- select,
- fattr_select;
- bool nphack = false;
- List *q;
-
- Assert(length(rel->relids) == 1); /* must be a base rel */
- relid = lfirsti(rel->relids);
-
- baserelid = getrelid(relid, root->rtable);
- indexrelid = index->indexoid;
-
- indRel = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(indexrelid),
- 0, 0, 0);
- if (!HeapTupleIsValid(indRel))
- elog(ERROR, "index_selectivity: index %u not found in pg_class",
- indexrelid);
- indexrelation = (Form_pg_class) GETSTRUCT(indRel);
- relam = indexrelation->relam;
-
- indexTuple = SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(indexrelid),
- 0, 0, 0);
- if (!HeapTupleIsValid(indexTuple))
- elog(ERROR, "index_selectivity: index %u not found in pg_index",
- indexrelid);
- pgindex = (Form_pg_index) GETSTRUCT(indexTuple);
-
- nIndexKeys = 1;
- while (pgindex->indclass[nIndexKeys] != InvalidOid)
- nIndexKeys++;
-
- /*
- * Hack for non-functional btree npages estimation: npages =
- * index_pages * selectivity_of_1st_attr_clause(s) - vadim 04/24/97
- */
- if (relam == BTREE_AM_OID && pgindex->indproc == InvalidOid)
- nphack = true;
-
- npages = 0.0;
- select = 1.0;
- fattr_select = 1.0;
-
- foreach(q, indexquals)
- {
- Node *expr = (Node *) lfirst(q);
- Oid opno;
- int dummyrelid;
- AttrNumber attno;
- Datum value;
- int flag;
- Oid indclass;
- HeapTuple amopTuple;
- Form_pg_amop amop;
- float64 amopnpages,
- amopselect;
-
- /*
- * Extract info from clause.
- */
- if (is_opclause(expr))
- opno = ((Oper *) ((Expr *) expr)->oper)->opno;
- else
- opno = InvalidOid;
- get_relattval(expr, relid, &dummyrelid, &attno, &value, &flag);
-
- /*
- * Find the AM class for this key.
- */
- if (pgindex->indproc != InvalidOid)
- {
- /*
- * Functional index: AM class is the first one defined since
- * functional indices have exactly one key.
- */
- indclass = pgindex->indclass[0];
- }
- else
- {
- int i;
- indclass = InvalidOid;
- for (i = 0; pgindex->indkey[i]; i++)
- {
- if (attno == pgindex->indkey[i])
- {
- indclass = pgindex->indclass[i];
- break;
- }
- }
- }
- if (!OidIsValid(indclass))
- {
- /*
- * Presumably this means that we are using a functional index
- * clause and so had no variable to match to the index key ...
- * if not we are in trouble.
- */
- elog(NOTICE, "index_selectivity: no key %d in index %u",
- attno, indexrelid);
- continue;
- }
-
- amopTuple = SearchSysCacheTuple(AMOPOPID,
- ObjectIdGetDatum(indclass),
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(relam),
- 0);
- if (!HeapTupleIsValid(amopTuple))
- {
- /*
- * We might get here because indxpath.c selected a binary-
- * compatible index. Try again with the compatible operator.
- */
- if (opno != InvalidOid)
- {
- opno = indexable_operator((Expr *) expr, indclass, relam,
- ((flag & SEL_RIGHT) != 0));
- amopTuple = SearchSysCacheTuple(AMOPOPID,
- ObjectIdGetDatum(indclass),
- ObjectIdGetDatum(opno),
- ObjectIdGetDatum(relam),
- 0);
- }
- if (!HeapTupleIsValid(amopTuple))
- elog(ERROR, "index_selectivity: no amop %u %u %u",
- indclass, opno, relam);
- }
- amop = (Form_pg_amop) GETSTRUCT(amopTuple);
-
- if (!nphack)
- {
- amopnpages = (float64) fmgr(amop->amopnpages,
- (char *) opno,
- (char *) baserelid,
- (char *) (int) attno,
- (char *) value,
- (char *) flag,
- (char *) nIndexKeys,
- (char *) indexrelid);
- if (PointerIsValid(amopnpages))
- npages += *amopnpages;
- }
-
- amopselect = (float64) fmgr(amop->amopselect,
- (char *) opno,
- (char *) baserelid,
- (char *) (int) attno,
- (char *) value,
- (char *) flag,
- (char *) nIndexKeys,
- (char *) indexrelid);
- if (PointerIsValid(amopselect))
- {
- select *= *amopselect;
- if (nphack && attno == pgindex->indkey[0])
- fattr_select *= *amopselect;
- }
- }
-
- /*
- * Estimation of npages below is hack of course, but it's better than
- * it was before. - vadim 04/09/97
- */
- if (nphack)
- {
- npages = fattr_select * indexrelation->relpages;
- *idxPages = (long) ceil((double) npages);
- }
- else
- {
- if (nIndexKeys > 1)
- npages = npages / (1.0 + nIndexKeys);
- *idxPages = (long) ceil((double) (npages / nIndexKeys));
- }
- *idxSelec = select;
-}
-
-/*
* restriction_selectivity
*
* Returns the selectivity of a specified operator.
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 338d93a7ffa..fb226fa41af 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.139 2000/01/09 12:17:33 ishii Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.140 2000/01/22 23:50:18 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1055,19 +1055,22 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
switch (optarg[0])
{
case 's': /* seqscan */
- _enable_seqscan_ = false;
+ enable_seqscan = false;
break;
case 'i': /* indexscan */
- _enable_indexscan_ = false;
+ enable_indexscan = false;
+ break;
+ case 't': /* tidscan */
+ enable_tidscan = false;
break;
case 'n': /* nestloop */
- _enable_nestloop_ = false;
+ enable_nestloop = false;
break;
case 'm': /* mergejoin */
- _enable_mergejoin_ = false;
+ enable_mergejoin = false;
break;
case 'h': /* hashjoin */
- _enable_hashjoin_ = false;
+ enable_hashjoin = false;
break;
default:
errs++;
@@ -1512,7 +1515,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.139 $ $Date: 2000/01/09 12:17:33 $\n");
+ puts("$Revision: 1.140 $ $Date: 2000/01/22 23:50:18 $\n");
}
/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 7ec3e4dc1b8..f1c458b761c 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -1,16 +1,20 @@
/*-------------------------------------------------------------------------
*
* selfuncs.c
- * Selectivity functions for system catalogs and builtin types
+ * Selectivity functions and index cost estimation functions for
+ * standard operators and index access methods.
*
- * These routines are registered in the operator catalog in the
- * "oprrest" and "oprjoin" attributes.
+ * Selectivity routines are registered in the pg_operator catalog
+ * in the "oprrest" and "oprjoin" attributes.
+ *
+ * Index cost functions are registered in the pg_am catalog
+ * in the "amcostestimate" attribute.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.48 2000/01/15 22:43:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.49 2000/01/22 23:50:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,6 +27,7 @@
#include "catalog/pg_proc.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_type.h"
+#include "optimizer/cost.h"
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "utils/builtins.h"
@@ -700,349 +705,74 @@ getattstatistics(Oid relid, AttrNumber attnum, Oid opid, Oid typid,
return true;
}
-float64
-btreesel(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
-{
- float64 result;
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber))
- {
-
- /*
- * Need to call the functions selectivity function here. For now
- * simply assume it's 1/3 since functions don't currently have
- * selectivity functions
- */
- result = (float64) palloc(sizeof(float64data));
- *result = 1.0 / 3.0;
- }
- else
- {
- RegProcedure oprrest = get_oprrest(operatorObjectId);
-
- /*
- * Operators used for indexes should have selectivity estimators.
- * (An alternative is to default to 0.5, as the optimizer does in
- * dealing with operators occurring in WHERE clauses, but if you
- * are going to the trouble of making index support you probably
- * don't want to miss the benefits of a good selectivity estimate.)
- */
- if (!oprrest)
- {
-#if 1
- /*
- * XXX temporary fix for 6.5: rtree operators are missing their
- * selectivity estimators, so return a default estimate instead.
- * Ugh.
- */
- result = (float64) palloc(sizeof(float64data));
- *result = 0.5;
-#else
- elog(ERROR,
- "Operator %u must have a restriction selectivity estimator to be used in an index",
- operatorObjectId);
-#endif
- }
- else
- result = (float64) fmgr(oprrest,
- (char *) operatorObjectId,
- (char *) indrelid,
- (char *) (int) attributeNumber,
- (char *) constValue,
- (char *) constFlag,
- NULL);
- }
-
- if (!PointerIsValid(result))
- elog(ERROR, "Btree Selectivity: bad pointer");
- if (*result < 0.0 || *result > 1.0)
- elog(ERROR, "Btree Selectivity: bad value %f", *result);
-
- return result;
-}
-
-float64
-btreenpage(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
-{
- float64 temp,
- result;
- float64data tempData;
- HeapTuple atp;
- int npage;
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber))
- {
-
- /*
- * Need to call the functions selectivity function here. For now
- * simply assume it's 1/3 since functions don't currently have
- * selectivity functions
- */
- tempData = 1.0 / 3.0;
- temp = &tempData;
- }
- else
- {
- RegProcedure oprrest = get_oprrest(operatorObjectId);
-
- /*
- * Operators used for indexes should have selectivity estimators.
- * (An alternative is to default to 0.5, as the optimizer does in
- * dealing with operators occurring in WHERE clauses, but if you
- * are going to the trouble of making index support you probably
- * don't want to miss the benefits of a good selectivity estimate.)
- */
- if (!oprrest)
- {
-#if 1
- /*
- * XXX temporary fix for 6.5: rtree operators are missing their
- * selectivity estimators, so return a default estimate instead.
- * Ugh.
- */
- tempData = 0.5;
- temp = &tempData;
-#else
- elog(ERROR,
- "Operator %u must have a restriction selectivity estimator to be used in an index",
- operatorObjectId);
-#endif
- }
- else
- temp = (float64) fmgr(oprrest,
- (char *) operatorObjectId,
- (char *) indrelid,
- (char *) (int) attributeNumber,
- (char *) constValue,
- (char *) constFlag,
- NULL);
- }
-
- atp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(indexrelid),
- 0, 0, 0);
- if (!HeapTupleIsValid(atp))
- {
- elog(ERROR, "btreenpage: no index tuple %u", indexrelid);
- return 0;
- }
-
- npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
- result = (float64) palloc(sizeof(float64data));
- *result = *temp * npage;
- return result;
-}
-
-float64
-hashsel(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
-{
-
- float64 result;
- float64data resultData;
- HeapTuple atp;
- int ntuples;
-
- if (FunctionalSelectivity(nIndexKeys, attributeNumber))
- {
-
- /*
- * Need to call the functions selectivity function here. For now
- * simply use 1/Number of Tuples since functions don't currently
- * have selectivity functions
- */
-
- atp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(indexrelid),
- 0, 0, 0);
- if (!HeapTupleIsValid(atp))
- {
- elog(ERROR, "hashsel: no index tuple %u", indexrelid);
- return 0;
- }
- ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
- if (ntuples > 0)
- resultData = 1.0 / (float64data) ntuples;
- else
- resultData = (float64data) (1.0 / 100.0);
- result = &resultData;
-
- }
- else
- {
- RegProcedure oprrest = get_oprrest(operatorObjectId);
-
- /*
- * Operators used for indexes should have selectivity estimators.
- * (An alternative is to default to 0.5, as the optimizer does in
- * dealing with operators occurring in WHERE clauses, but if you
- * are going to the trouble of making index support you probably
- * don't want to miss the benefits of a good selectivity estimate.)
- */
- if (!oprrest)
- elog(ERROR,
- "Operator %u must have a restriction selectivity estimator to be used in a hash index",
- operatorObjectId);
-
- result = (float64) fmgr(oprrest,
- (char *) operatorObjectId,
- (char *) indrelid,
- (char *) (int) attributeNumber,
- (char *) constValue,
- (char *) constFlag,
- NULL);
- }
-
- if (!PointerIsValid(result))
- elog(ERROR, "Hash Table Selectivity: bad pointer");
- if (*result < 0.0 || *result > 1.0)
- elog(ERROR, "Hash Table Selectivity: bad value %f", *result);
-
- return result;
-
-
-}
+/*-------------------------------------------------------------------------
+ *
+ * Index cost estimation functions
+ *
+ * genericcostestimate is a general-purpose estimator for use when we
+ * don't have any better idea about how to estimate. Index-type-specific
+ * knowledge can be incorporated in the type-specific routines.
+ *
+ *-------------------------------------------------------------------------
+ */
-float64
-hashnpage(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+static void
+genericcostestimate(Query *root, RelOptInfo *rel,
+ IndexOptInfo *index, List *indexQuals,
+ Cost *indexAccessCost, Selectivity *indexSelectivity)
{
- float64 temp,
- result;
- float64data tempData;
- HeapTuple atp;
- int npage;
- int ntuples;
-
- atp = SearchSysCacheTuple(RELOID,
- ObjectIdGetDatum(indexrelid),
- 0, 0, 0);
- if (!HeapTupleIsValid(atp))
- {
- elog(ERROR, "hashsel: no index tuple %u", indexrelid);
- return 0;
- }
+ double numIndexTuples;
+ double numIndexPages;
+ /* Estimate the fraction of main-table tuples that will be visited */
+ *indexSelectivity = clauselist_selec(root, indexQuals);
- if (FunctionalSelectivity(nIndexKeys, attributeNumber))
- {
-
- /*
- * Need to call the functions selectivity function here. For now,
- * use 1/Number of Tuples since functions don't currently have
- * selectivity functions
- */
-
- ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
- if (ntuples > 0)
- tempData = 1.0 / (float64data) ntuples;
- else
- tempData = (float64data) (1.0 / 100.0);
- temp = &tempData;
-
- }
- else
- {
- RegProcedure oprrest = get_oprrest(operatorObjectId);
+ /* Estimate the number of index tuples that will be visited */
+ numIndexTuples = *indexSelectivity * index->tuples;
- /*
- * Operators used for indexes should have selectivity estimators.
- * (An alternative is to default to 0.5, as the optimizer does in
- * dealing with operators occurring in WHERE clauses, but if you
- * are going to the trouble of making index support you probably
- * don't want to miss the benefits of a good selectivity estimate.)
- */
- if (!oprrest)
- elog(ERROR,
- "Operator %u must have a restriction selectivity estimator to be used in a hash index",
- operatorObjectId);
-
- temp = (float64) fmgr(oprrest,
- (char *) operatorObjectId,
- (char *) indrelid,
- (char *) (int) attributeNumber,
- (char *) constValue,
- (char *) constFlag,
- NULL);
- }
+ /* Estimate the number of index pages that will be retrieved */
+ numIndexPages = *indexSelectivity * index->pages;
- npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
- result = (float64) palloc(sizeof(float64data));
- *result = *temp * npage;
- return result;
+ /* Compute the index access cost */
+ *indexAccessCost = numIndexPages + cpu_index_page_weight * numIndexTuples;
}
+/*
+ * For first cut, just use generic function for all index types.
+ */
-float64
-rtsel(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+void
+btcostestimate(Query *root, RelOptInfo *rel,
+ IndexOptInfo *index, List *indexQuals,
+ Cost *indexAccessCost, Selectivity *indexSelectivity)
{
- return (btreesel(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
+ genericcostestimate(root, rel, index, indexQuals,
+ indexAccessCost, indexSelectivity);
}
-float64
-rtnpage(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+void
+rtcostestimate(Query *root, RelOptInfo *rel,
+ IndexOptInfo *index, List *indexQuals,
+ Cost *indexAccessCost, Selectivity *indexSelectivity)
{
- return (btreenpage(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
+ genericcostestimate(root, rel, index, indexQuals,
+ indexAccessCost, indexSelectivity);
}
-float64
-gistsel(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+void
+hashcostestimate(Query *root, RelOptInfo *rel,
+ IndexOptInfo *index, List *indexQuals,
+ Cost *indexAccessCost, Selectivity *indexSelectivity)
{
- return (btreesel(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
+ genericcostestimate(root, rel, index, indexQuals,
+ indexAccessCost, indexSelectivity);
}
-float64
-gistnpage(Oid operatorObjectId,
- Oid indrelid,
- AttrNumber attributeNumber,
- char *constValue,
- int32 constFlag,
- int32 nIndexKeys,
- Oid indexrelid)
+void
+gistcostestimate(Query *root, RelOptInfo *rel,
+ IndexOptInfo *index, List *indexQuals,
+ Cost *indexAccessCost, Selectivity *indexSelectivity)
{
- return (btreenpage(operatorObjectId, indrelid, attributeNumber,
- constValue, constFlag, nIndexKeys, indexrelid));
+ genericcostestimate(root, rel, index, indexQuals,
+ indexAccessCost, indexSelectivity);
}