mirror of
https://github.com/postgres/postgres.git
synced 2025-11-15 03:41:20 +03:00
First cut at making indexscan cost estimates depend on correlation
between index order and table order.
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.88 2001/05/07 00:43:23 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.89 2001/05/09 23:13:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "optimizer/cost.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_oper.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/date.h"
|
||||
#include "utils/int8.h"
|
||||
@@ -818,7 +819,6 @@ eqjoinsel(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#ifdef NOT_USED /* see neqjoinsel() before removing me! */
|
||||
Oid opid = PG_GETARG_OID(0);
|
||||
|
||||
#endif
|
||||
Oid relid1 = PG_GETARG_OID(1);
|
||||
AttrNumber attno1 = PG_GETARG_INT16(2);
|
||||
@@ -2230,16 +2230,14 @@ string_to_datum(const char *str, Oid datatype)
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
static Datum
|
||||
genericcostestimate(PG_FUNCTION_ARGS)
|
||||
static void
|
||||
genericcostestimate(Query *root, RelOptInfo *rel,
|
||||
IndexOptInfo *index, List *indexQuals,
|
||||
Cost *indexStartupCost,
|
||||
Cost *indexTotalCost,
|
||||
Selectivity *indexSelectivity,
|
||||
double *indexCorrelation)
|
||||
{
|
||||
Query *root = (Query *) PG_GETARG_POINTER(0);
|
||||
RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1);
|
||||
IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2);
|
||||
List *indexQuals = (List *) PG_GETARG_POINTER(3);
|
||||
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4);
|
||||
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5);
|
||||
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6);
|
||||
double numIndexTuples;
|
||||
double numIndexPages;
|
||||
|
||||
@@ -2275,33 +2273,134 @@ genericcostestimate(PG_FUNCTION_ARGS)
|
||||
*indexTotalCost = numIndexPages +
|
||||
(cpu_index_tuple_cost + cost_qual_eval(indexQuals)) * numIndexTuples;
|
||||
|
||||
PG_RETURN_VOID();
|
||||
/*
|
||||
* Generic assumption about index correlation: there isn't any.
|
||||
*/
|
||||
*indexCorrelation = 0.0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For first cut, just use generic function for all index types.
|
||||
*/
|
||||
|
||||
Datum
|
||||
btcostestimate(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return genericcostestimate(fcinfo);
|
||||
Query *root = (Query *) PG_GETARG_POINTER(0);
|
||||
RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1);
|
||||
IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2);
|
||||
List *indexQuals = (List *) PG_GETARG_POINTER(3);
|
||||
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4);
|
||||
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5);
|
||||
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6);
|
||||
double *indexCorrelation = (double *) PG_GETARG_POINTER(7);
|
||||
|
||||
genericcostestimate(root, rel, index, indexQuals,
|
||||
indexStartupCost, indexTotalCost,
|
||||
indexSelectivity, indexCorrelation);
|
||||
|
||||
/*
|
||||
* If it's a functional index, leave the default zero-correlation
|
||||
* estimate in place. If not, and if we can get an estimate for
|
||||
* the first variable's ordering correlation C from pg_statistic,
|
||||
* estimate the index correlation as C / number-of-columns.
|
||||
* (The idea here is that multiple columns dilute the importance
|
||||
* of the first column's ordering, but don't negate it entirely.)
|
||||
*/
|
||||
if (index->indproc == InvalidOid)
|
||||
{
|
||||
Oid relid;
|
||||
HeapTuple tuple;
|
||||
|
||||
relid = getrelid(lfirsti(rel->relids), root->rtable);
|
||||
Assert(relid != InvalidOid);
|
||||
tuple = SearchSysCache(STATRELATT,
|
||||
ObjectIdGetDatum(relid),
|
||||
Int16GetDatum(index->indexkeys[0]),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
Oid typid;
|
||||
int32 typmod;
|
||||
float4 *numbers;
|
||||
int nnumbers;
|
||||
|
||||
get_atttypetypmod(relid, index->indexkeys[0],
|
||||
&typid, &typmod);
|
||||
if (get_attstatsslot(tuple, typid, typmod,
|
||||
STATISTIC_KIND_CORRELATION,
|
||||
index->ordering[0],
|
||||
NULL, NULL, &numbers, &nnumbers))
|
||||
{
|
||||
double varCorrelation;
|
||||
int nKeys;
|
||||
|
||||
Assert(nnumbers == 1);
|
||||
varCorrelation = numbers[0];
|
||||
for (nKeys = 1; index->indexkeys[nKeys] != 0; nKeys++)
|
||||
/*skip*/;
|
||||
|
||||
*indexCorrelation = varCorrelation / nKeys;
|
||||
|
||||
free_attstatsslot(typid, NULL, 0, numbers, nnumbers);
|
||||
}
|
||||
ReleaseSysCache(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
Datum
|
||||
rtcostestimate(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return genericcostestimate(fcinfo);
|
||||
Query *root = (Query *) PG_GETARG_POINTER(0);
|
||||
RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1);
|
||||
IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2);
|
||||
List *indexQuals = (List *) PG_GETARG_POINTER(3);
|
||||
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4);
|
||||
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5);
|
||||
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6);
|
||||
double *indexCorrelation = (double *) PG_GETARG_POINTER(7);
|
||||
|
||||
genericcostestimate(root, rel, index, indexQuals,
|
||||
indexStartupCost, indexTotalCost,
|
||||
indexSelectivity, indexCorrelation);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
Datum
|
||||
hashcostestimate(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return genericcostestimate(fcinfo);
|
||||
Query *root = (Query *) PG_GETARG_POINTER(0);
|
||||
RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1);
|
||||
IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2);
|
||||
List *indexQuals = (List *) PG_GETARG_POINTER(3);
|
||||
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4);
|
||||
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5);
|
||||
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6);
|
||||
double *indexCorrelation = (double *) PG_GETARG_POINTER(7);
|
||||
|
||||
genericcostestimate(root, rel, index, indexQuals,
|
||||
indexStartupCost, indexTotalCost,
|
||||
indexSelectivity, indexCorrelation);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
Datum
|
||||
gistcostestimate(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return genericcostestimate(fcinfo);
|
||||
Query *root = (Query *) PG_GETARG_POINTER(0);
|
||||
RelOptInfo *rel = (RelOptInfo *) PG_GETARG_POINTER(1);
|
||||
IndexOptInfo *index = (IndexOptInfo *) PG_GETARG_POINTER(2);
|
||||
List *indexQuals = (List *) PG_GETARG_POINTER(3);
|
||||
Cost *indexStartupCost = (Cost *) PG_GETARG_POINTER(4);
|
||||
Cost *indexTotalCost = (Cost *) PG_GETARG_POINTER(5);
|
||||
Selectivity *indexSelectivity = (Selectivity *) PG_GETARG_POINTER(6);
|
||||
double *indexCorrelation = (double *) PG_GETARG_POINTER(7);
|
||||
|
||||
genericcostestimate(root, rel, index, indexQuals,
|
||||
indexStartupCost, indexTotalCost,
|
||||
indexSelectivity, indexCorrelation);
|
||||
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
32
src/backend/utils/cache/lsyscache.c
vendored
32
src/backend/utils/cache/lsyscache.c
vendored
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.54 2001/05/09 00:35:09 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.55 2001/05/09 23:13:35 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Eventually, the index information should go through here, too.
|
||||
@@ -185,6 +185,36 @@ get_atttypmod(Oid relid, AttrNumber attnum)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_atttypetypmod
|
||||
*
|
||||
* A two-fer: given the relation id and the attribute number,
|
||||
* fetch both type OID and atttypmod in a single cache lookup.
|
||||
*
|
||||
* Unlike the otherwise-similar get_atttype/get_atttypmod, this routine
|
||||
* raises an error if it can't obtain the information.
|
||||
*/
|
||||
void
|
||||
get_atttypetypmod(Oid relid, AttrNumber attnum,
|
||||
Oid *typid, int32 *typmod)
|
||||
{
|
||||
HeapTuple tp;
|
||||
Form_pg_attribute att_tup;
|
||||
|
||||
tp = SearchSysCache(ATTNUM,
|
||||
ObjectIdGetDatum(relid),
|
||||
Int16GetDatum(attnum),
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(tp))
|
||||
elog(ERROR, "cache lookup failed for relation %u attribute %d",
|
||||
relid, attnum);
|
||||
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
|
||||
|
||||
*typid = att_tup->atttypid;
|
||||
*typmod = att_tup->atttypmod;
|
||||
ReleaseSysCache(tp);
|
||||
}
|
||||
|
||||
/* ---------- INDEX CACHE ---------- */
|
||||
|
||||
/* watch this space...
|
||||
|
||||
Reference in New Issue
Block a user