diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-02-03 15:07:08 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-02-03 15:07:08 +0000 |
commit | 4cff59d8d540c441fb0c22dfaa517bc25aa5f794 (patch) | |
tree | 88b4c216d219582904d3d9d6a236bb9468fe148c /src/backend/optimizer/util | |
parent | 0d3e36b6687ae601551fb8047c10a68f2d6fb565 (diff) | |
download | postgresql-4cff59d8d540c441fb0c22dfaa517bc25aa5f794.tar.gz postgresql-4cff59d8d540c441fb0c22dfaa517bc25aa5f794.zip |
Tweak planner and executor to avoid doing ExecProject() in table scan
nodes where it's not really necessary. In many cases where the scan node
is not the topmost plan node (eg, joins, aggregation), it's possible to
just return the table tuple directly instead of generating an intermediate
projection tuple. In preliminary testing, this reduced the CPU time
needed for 'SELECT COUNT(*) FROM foo' by about 10%.
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r-- | src/backend/optimizer/util/plancat.c | 248 | ||||
-rw-r--r-- | src/backend/optimizer/util/relnode.c | 17 |
2 files changed, 133 insertions, 132 deletions
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 4a9f63312c3..3e0bbe69225 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.76 2003/01/28 22:13:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.77 2003/02/03 15:07:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -23,6 +23,7 @@ #include "catalog/pg_amop.h" #include "catalog/pg_inherits.h" #include "catalog/pg_index.h" +#include "nodes/makefuncs.h" #include "optimizer/clauses.h" #include "optimizer/plancat.h" #include "parser/parsetree.h" @@ -38,155 +39,160 @@ /* * get_relation_info - * Retrieves catalog information for a given relation. - * Given the Oid of the relation, return the following info: - * whether the relation has secondary indices - * number of pages - * number of tuples - */ -void -get_relation_info(Oid relationObjectId, - bool *hasindex, long *pages, double *tuples) -{ - HeapTuple relationTuple; - Form_pg_class relation; - - relationTuple = SearchSysCache(RELOID, - ObjectIdGetDatum(relationObjectId), - 0, 0, 0); - if (!HeapTupleIsValid(relationTuple)) - elog(ERROR, "get_relation_info: Relation %u not found", - relationObjectId); - relation = (Form_pg_class) GETSTRUCT(relationTuple); - - if (IsIgnoringSystemIndexes() && IsSystemClass(relation)) - *hasindex = false; - else - *hasindex = relation->relhasindex; - - *pages = relation->relpages; - *tuples = relation->reltuples; - - ReleaseSysCache(relationTuple); -} - -/* - * find_secondary_indexes - * Creates a list of IndexOptInfo nodes containing information for each - * secondary index defined on the specified relation. * - * 'relationObjectId' is the OID of the relation for which indices are wanted + * Given the Oid of the relation, return the following info into fields + * of the RelOptInfo struct: * - * Returns a list of new IndexOptInfo nodes. + * varlist list of physical columns (expressed as Vars) + * indexlist list of IndexOptInfos for relation's indexes + * pages number of pages + * tuples number of tuples */ -List * -find_secondary_indexes(Oid relationObjectId) +void +get_relation_info(Oid relationObjectId, RelOptInfo *rel) { - List *indexinfos = NIL; - List *indexoidlist, - *indexoidscan; Relation relation; + Index varno = lfirsti(rel->relids); + bool hasindex; + List *varlist = NIL; + List *indexinfos = NIL; + int attrno, + numattrs; + + relation = heap_open(relationObjectId, AccessShareLock); /* - * We used to scan pg_index directly, but now the relcache offers a - * cached list of OID indexes for each relation. So, get that list - * and then use the syscache to obtain pg_index entries. + * Make list of physical Vars. Note we do NOT ignore dropped columns; + * the intent is to model the physical tuples of the relation. */ - relation = heap_open(relationObjectId, AccessShareLock); - indexoidlist = RelationGetIndexList(relation); + numattrs = RelationGetNumberOfAttributes(relation); - foreach(indexoidscan, indexoidlist) + for (attrno = 1; attrno <= numattrs; attrno++) { - Oid indexoid = lfirsti(indexoidscan); - Relation indexRelation; - Form_pg_index index; - IndexOptInfo *info; - int i; - int16 amorderstrategy; - - /* Extract info from the relation descriptor for the index */ - indexRelation = index_open(indexoid); + Form_pg_attribute att_tup = relation->rd_att->attrs[attrno - 1]; + + varlist = lappend(varlist, + makeVar(varno, + attrno, + att_tup->atttypid, + att_tup->atttypmod, + 0)); + } - info = makeNode(IndexOptInfo); + rel->varlist = varlist; - /* - * Need to make these arrays large enough to be sure there is room - * for a terminating 0 at the end of each one. - */ - info->classlist = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS + 1)); - info->indexkeys = (int *) palloc(sizeof(int) * (INDEX_MAX_KEYS + 1)); - info->ordering = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS + 1)); - - /* Extract info from the pg_index tuple */ - index = indexRelation->rd_index; - info->indexoid = index->indexrelid; - info->indproc = index->indproc; /* functional index ?? */ - if (VARSIZE(&index->indpred) > VARHDRSZ) /* partial index ?? */ - { - char *predString; + /* + * Make list of indexes. Ignore indexes on system catalogs if told to. + */ + if (IsIgnoringSystemIndexes() && IsSystemClass(relation->rd_rel)) + hasindex = false; + else + hasindex = relation->rd_rel->relhasindex; - predString = DatumGetCString(DirectFunctionCall1(textout, - PointerGetDatum(&index->indpred))); - info->indpred = (List *) stringToNode(predString); - pfree(predString); - } - else - info->indpred = NIL; - info->unique = index->indisunique; + if (hasindex) + { + List *indexoidlist, + *indexoidscan; - for (i = 0; i < INDEX_MAX_KEYS; i++) - { - if (index->indclass[i] == (Oid) 0) - break; - info->classlist[i] = index->indclass[i]; - } - info->classlist[i] = (Oid) 0; - info->ncolumns = i; + indexoidlist = RelationGetIndexList(relation); - for (i = 0; i < INDEX_MAX_KEYS; i++) + foreach(indexoidscan, indexoidlist) { - if (index->indkey[i] == 0) - break; - info->indexkeys[i] = index->indkey[i]; - } - info->indexkeys[i] = 0; - info->nkeys = i; + Oid indexoid = lfirsti(indexoidscan); + Relation indexRelation; + Form_pg_index index; + IndexOptInfo *info; + int i; + int16 amorderstrategy; + + /* Extract info from the relation descriptor for the index */ + indexRelation = index_open(indexoid); + + info = makeNode(IndexOptInfo); + + /* + * Need to make these arrays large enough to be sure there is room + * for a terminating 0 at the end of each one. + */ + info->classlist = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS + 1)); + info->indexkeys = (int *) palloc(sizeof(int) * (INDEX_MAX_KEYS + 1)); + info->ordering = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS + 1)); + + /* Extract info from the pg_index tuple */ + index = indexRelation->rd_index; + info->indexoid = index->indexrelid; + info->indproc = index->indproc; /* functional index ?? */ + if (VARSIZE(&index->indpred) > VARHDRSZ) /* partial index ?? */ + { + char *predString; - info->relam = indexRelation->rd_rel->relam; - info->pages = indexRelation->rd_rel->relpages; - info->tuples = indexRelation->rd_rel->reltuples; - info->amcostestimate = index_cost_estimator(indexRelation); - amorderstrategy = indexRelation->rd_am->amorderstrategy; + predString = DatumGetCString(DirectFunctionCall1(textout, + PointerGetDatum(&index->indpred))); + info->indpred = (List *) stringToNode(predString); + pfree(predString); + } + else + info->indpred = NIL; + info->unique = index->indisunique; - /* - * Fetch the ordering operators associated with the index, if any. - */ - MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS + 1)); - if (amorderstrategy != 0) - { - int oprindex = amorderstrategy - 1; + for (i = 0; i < INDEX_MAX_KEYS; i++) + { + if (index->indclass[i] == (Oid) 0) + break; + info->classlist[i] = index->indclass[i]; + } + info->classlist[i] = (Oid) 0; + info->ncolumns = i; - for (i = 0; i < info->ncolumns; i++) + for (i = 0; i < INDEX_MAX_KEYS; i++) { - info->ordering[i] = indexRelation->rd_operator[oprindex]; - oprindex += indexRelation->rd_am->amstrategies; + if (index->indkey[i] == 0) + break; + info->indexkeys[i] = index->indkey[i]; } - } + info->indexkeys[i] = 0; + info->nkeys = i; + + info->relam = indexRelation->rd_rel->relam; + info->pages = indexRelation->rd_rel->relpages; + info->tuples = indexRelation->rd_rel->reltuples; + info->amcostestimate = index_cost_estimator(indexRelation); + amorderstrategy = indexRelation->rd_am->amorderstrategy; + + /* + * Fetch the ordering operators associated with the index, if any. + */ + MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS + 1)); + if (amorderstrategy != 0) + { + int oprindex = amorderstrategy - 1; - /* initialize cached join info to empty */ - info->outer_relids = NIL; - info->inner_paths = NIL; + for (i = 0; i < info->ncolumns; i++) + { + info->ordering[i] = indexRelation->rd_operator[oprindex]; + oprindex += indexRelation->rd_am->amstrategies; + } + } - index_close(indexRelation); + /* initialize cached join info to empty */ + info->outer_relids = NIL; + info->inner_paths = NIL; - indexinfos = lcons(info, indexinfos); + index_close(indexRelation); + + indexinfos = lcons(info, indexinfos); + } + + freeList(indexoidlist); } - freeList(indexoidlist); + rel->indexlist = indexinfos; + + rel->pages = relation->rd_rel->relpages; + rel->tuples = relation->rd_rel->reltuples; /* XXX keep the lock here? */ heap_close(relation, AccessShareLock); - - return indexinfos; } /* diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index 06a73bf4e9e..ebfaa4924d4 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.45 2003/01/24 03:58:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.46 2003/02/03 15:07:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -143,6 +143,7 @@ make_base_rel(Query *root, int relid) rel->cheapest_unique_path = NULL; rel->pruneable = true; rel->rtekind = rte->rtekind; + rel->varlist = NIL; rel->indexlist = NIL; rel->pages = 0; rel->tuples = 0; @@ -159,16 +160,9 @@ make_base_rel(Query *root, int relid) switch (rte->rtekind) { case RTE_RELATION: - { - /* Table --- retrieve statistics from the system catalogs */ - bool indexed; - - get_relation_info(rte->relid, - &indexed, &rel->pages, &rel->tuples); - if (indexed) - rel->indexlist = find_secondary_indexes(rte->relid); - break; - } + /* Table --- retrieve statistics from the system catalogs */ + get_relation_info(rte->relid, rel); + break; case RTE_SUBQUERY: case RTE_FUNCTION: /* Subquery or function --- nothing to do here */ @@ -304,6 +298,7 @@ build_join_rel(Query *root, joinrel->cheapest_unique_path = NULL; joinrel->pruneable = true; joinrel->rtekind = RTE_JOIN; + joinrel->varlist = NIL; joinrel->indexlist = NIL; joinrel->pages = 0; joinrel->tuples = 0; |