mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Revise handling of index-type-specific indexscan cost estimation, per
pghackers discussion of 5-Jan-2000. The amopselect and amopnpages estimators are gone, and in their place is a per-AM amcostestimate procedure (linked to from pg_am, not pg_amop).
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
/*
|
||||
@@ -168,216 +169,6 @@ find_secondary_indexes(Query *root, Index relid)
|
||||
return indexes;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user