Commit 166b5c1d authored by Tom Lane's avatar Tom Lane

Another round of planner/optimizer work. This is just restructuring and

code cleanup; no major improvements yet.  However, EXPLAIN does produce
more intuitive outputs for nested loops with indexscans now...
parent 69d4299e
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* Copyright (c) 1994-5, Regents of the University of California * Copyright (c) 1994-5, Regents of the University of California
* *
* $Id: explain.c,v 1.50 1999/11/23 20:06:48 momjian Exp $ * $Id: explain.c,v 1.51 2000/01/09 00:26:18 tgl Exp $
* *
*/ */
...@@ -256,8 +256,8 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es) ...@@ -256,8 +256,8 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
} }
if (es->printCost) if (es->printCost)
{ {
appendStringInfo(str, " (cost=%.2f rows=%d width=%d)", appendStringInfo(str, " (cost=%.2f rows=%.0f width=%d)",
plan->cost, plan->plan_size, plan->plan_width); plan->cost, plan->plan_rows, plan->plan_width);
} }
appendStringInfo(str, "\n"); appendStringInfo(str, "\n");
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* *
* $Id: nodeHash.c,v 1.41 1999/12/16 22:19:44 wieck Exp $ * $Id: nodeHash.c,v 1.42 2000/01/09 00:26:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -227,7 +227,7 @@ HashJoinTable ...@@ -227,7 +227,7 @@ HashJoinTable
ExecHashTableCreate(Hash *node) ExecHashTableCreate(Hash *node)
{ {
Plan *outerNode; Plan *outerNode;
int ntuples; double ntuples;
int tupsize; int tupsize;
double inner_rel_bytes; double inner_rel_bytes;
double hash_table_bytes; double hash_table_bytes;
...@@ -250,9 +250,9 @@ ExecHashTableCreate(Hash *node) ...@@ -250,9 +250,9 @@ ExecHashTableCreate(Hash *node)
* ---------------- * ----------------
*/ */
outerNode = outerPlan(node); outerNode = outerPlan(node);
ntuples = outerNode->plan_size; ntuples = outerNode->plan_rows;
if (ntuples <= 0) /* force a plausible size if no info */ if (ntuples <= 0.0) /* force a plausible size if no info */
ntuples = 1000; ntuples = 1000.0;
/* /*
* estimate tupsize based on footprint of tuple in hashtable... but * estimate tupsize based on footprint of tuple in hashtable... but
...@@ -260,7 +260,7 @@ ExecHashTableCreate(Hash *node) ...@@ -260,7 +260,7 @@ ExecHashTableCreate(Hash *node)
*/ */
tupsize = MAXALIGN(outerNode->plan_width) + tupsize = MAXALIGN(outerNode->plan_width) +
MAXALIGN(sizeof(HashJoinTupleData)); MAXALIGN(sizeof(HashJoinTupleData));
inner_rel_bytes = (double) ntuples *tupsize * FUDGE_FAC; inner_rel_bytes = ntuples * tupsize * FUDGE_FAC;
/* /*
* Target hashtable size is SortMem kilobytes, but not less than * Target hashtable size is SortMem kilobytes, but not less than
...@@ -276,7 +276,7 @@ ExecHashTableCreate(Hash *node) ...@@ -276,7 +276,7 @@ ExecHashTableCreate(Hash *node)
* for an average bucket load of NTUP_PER_BUCKET (per virtual * for an average bucket load of NTUP_PER_BUCKET (per virtual
* bucket!). * bucket!).
*/ */
totalbuckets = (int) ceil((double) ntuples * FUDGE_FAC / NTUP_PER_BUCKET); totalbuckets = (int) ceil(ntuples * FUDGE_FAC / NTUP_PER_BUCKET);
/* /*
* Count the number of buckets we think will actually fit in the * Count the number of buckets we think will actually fit in the
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.98 1999/12/13 01:26:53 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.99 2000/01/09 00:26:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -75,9 +75,9 @@ static void ...@@ -75,9 +75,9 @@ static void
CopyPlanFields(Plan *from, Plan *newnode) CopyPlanFields(Plan *from, Plan *newnode)
{ {
newnode->cost = from->cost; newnode->cost = from->cost;
newnode->plan_size = from->plan_size; newnode->plan_rows = from->plan_rows;
newnode->plan_width = from->plan_width; newnode->plan_width = from->plan_width;
newnode->plan_tupperpage = from->plan_tupperpage; /* state is NOT copied */
newnode->targetlist = copyObject(from->targetlist); newnode->targetlist = copyObject(from->targetlist);
newnode->qual = copyObject(from->qual); newnode->qual = copyObject(from->qual);
newnode->lefttree = copyObject(from->lefttree); newnode->lefttree = copyObject(from->lefttree);
...@@ -962,25 +962,44 @@ static RelOptInfo * ...@@ -962,25 +962,44 @@ static RelOptInfo *
_copyRelOptInfo(RelOptInfo *from) _copyRelOptInfo(RelOptInfo *from)
{ {
RelOptInfo *newnode = makeNode(RelOptInfo); RelOptInfo *newnode = makeNode(RelOptInfo);
int i,
len;
/* ----------------
* copy remainder of node
* ----------------
*/
newnode->relids = listCopy(from->relids); newnode->relids = listCopy(from->relids);
newnode->indexed = from->indexed; newnode->rows = from->rows;
newnode->pages = from->pages;
newnode->tuples = from->tuples;
newnode->size = from->size;
newnode->width = from->width; newnode->width = from->width;
Node_Copy(from, newnode, targetlist); Node_Copy(from, newnode, targetlist);
Node_Copy(from, newnode, pathlist); Node_Copy(from, newnode, pathlist);
/* XXX cheapestpath should point to a member of pathlist? */
Node_Copy(from, newnode, cheapestpath); Node_Copy(from, newnode, cheapestpath);
newnode->pruneable = from->pruneable; newnode->pruneable = from->pruneable;
newnode->indexed = from->indexed;
newnode->pages = from->pages;
newnode->tuples = from->tuples;
Node_Copy(from, newnode, restrictinfo);
Node_Copy(from, newnode, joininfo);
Node_Copy(from, newnode, innerjoin);
return newnode;
}
/* ----------------
* _copyIndexOptInfo
* ----------------
*/
static IndexOptInfo *
_copyIndexOptInfo(IndexOptInfo *from)
{
IndexOptInfo *newnode = makeNode(IndexOptInfo);
int i,
len;
newnode->indexoid = from->indexoid;
newnode->pages = from->pages;
newnode->tuples = from->tuples;
if (from->classlist) if (from->classlist)
{ {
for (len = 0; from->classlist[len] != 0; len++) for (len = 0; from->classlist[len] != 0; len++)
...@@ -1015,10 +1034,6 @@ _copyRelOptInfo(RelOptInfo *from) ...@@ -1015,10 +1034,6 @@ _copyRelOptInfo(RelOptInfo *from)
newnode->indproc = from->indproc; newnode->indproc = from->indproc;
Node_Copy(from, newnode, indpred); Node_Copy(from, newnode, indpred);
Node_Copy(from, newnode, restrictinfo);
Node_Copy(from, newnode, joininfo);
Node_Copy(from, newnode, innerjoin);
return newnode; return newnode;
} }
...@@ -1120,7 +1135,6 @@ _copyTidPath(TidPath *from) ...@@ -1120,7 +1135,6 @@ _copyTidPath(TidPath *from)
static void static void
CopyJoinPathFields(JoinPath *from, JoinPath *newnode) CopyJoinPathFields(JoinPath *from, JoinPath *newnode)
{ {
Node_Copy(from, newnode, pathinfo);
Node_Copy(from, newnode, outerjoinpath); Node_Copy(from, newnode, outerjoinpath);
Node_Copy(from, newnode, innerjoinpath); Node_Copy(from, newnode, innerjoinpath);
} }
...@@ -1229,7 +1243,6 @@ _copyRestrictInfo(RestrictInfo *from) ...@@ -1229,7 +1243,6 @@ _copyRestrictInfo(RestrictInfo *from)
* ---------------- * ----------------
*/ */
Node_Copy(from, newnode, clause); Node_Copy(from, newnode, clause);
newnode->selectivity = from->selectivity;
Node_Copy(from, newnode, subclauseindices); Node_Copy(from, newnode, subclauseindices);
newnode->mergejoinoperator = from->mergejoinoperator; newnode->mergejoinoperator = from->mergejoinoperator;
newnode->left_sortop = from->left_sortop; newnode->left_sortop = from->left_sortop;
...@@ -1617,6 +1630,9 @@ copyObject(void *from) ...@@ -1617,6 +1630,9 @@ copyObject(void *from)
case T_Stream: case T_Stream:
retval = _copyStream(from); retval = _copyStream(from);
break; break;
case T_IndexOptInfo:
retval = _copyIndexOptInfo(from);
break;
/* /*
* PARSE NODES * PARSE NODES
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.54 1999/12/24 06:43:32 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.55 2000/01/09 00:26:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -302,6 +302,17 @@ _equalRelOptInfo(RelOptInfo *a, RelOptInfo *b) ...@@ -302,6 +302,17 @@ _equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
return equali(a->relids, b->relids); return equali(a->relids, b->relids);
} }
static bool
_equalIndexOptInfo(IndexOptInfo *a, IndexOptInfo *b)
{
/* We treat IndexOptInfos as equal if they refer to the same index.
* Is this sufficient?
*/
if (a->indexoid != b->indexoid)
return false;
return true;
}
static bool static bool
_equalPathKeyItem(PathKeyItem *a, PathKeyItem *b) _equalPathKeyItem(PathKeyItem *a, PathKeyItem *b)
{ {
...@@ -358,8 +369,6 @@ _equalJoinPath(JoinPath *a, JoinPath *b) ...@@ -358,8 +369,6 @@ _equalJoinPath(JoinPath *a, JoinPath *b)
{ {
if (!_equalPath((Path *) a, (Path *) b)) if (!_equalPath((Path *) a, (Path *) b))
return false; return false;
if (!equal(a->pathinfo, b->pathinfo))
return false;
if (!equal(a->outerjoinpath, b->outerjoinpath)) if (!equal(a->outerjoinpath, b->outerjoinpath))
return false; return false;
if (!equal(a->innerjoinpath, b->innerjoinpath)) if (!equal(a->innerjoinpath, b->innerjoinpath))
...@@ -469,7 +478,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) ...@@ -469,7 +478,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
{ {
if (!equal(a->clause, b->clause)) if (!equal(a->clause, b->clause))
return false; return false;
/* do not check selectivity because of roundoff error worries */
if (!equal(a->subclauseindices, b->subclauseindices)) if (!equal(a->subclauseindices, b->subclauseindices))
return false; return false;
if (a->mergejoinoperator != b->mergejoinoperator) if (a->mergejoinoperator != b->mergejoinoperator)
...@@ -792,6 +800,9 @@ equal(void *a, void *b) ...@@ -792,6 +800,9 @@ equal(void *a, void *b)
case T_RelOptInfo: case T_RelOptInfo:
retval = _equalRelOptInfo(a, b); retval = _equalRelOptInfo(a, b);
break; break;
case T_IndexOptInfo:
retval = _equalIndexOptInfo(a, b);
break;
case T_PathKeyItem: case T_PathKeyItem:
retval = _equalPathKeyItem(a, b); retval = _equalPathKeyItem(a, b);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.29 1999/12/16 22:19:47 wieck Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.30 2000/01/09 00:26:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -730,11 +730,29 @@ _freeRelOptInfo(RelOptInfo *node) ...@@ -730,11 +730,29 @@ _freeRelOptInfo(RelOptInfo *node)
freeObject(node->targetlist); freeObject(node->targetlist);
freeObject(node->pathlist); freeObject(node->pathlist);
/* is this right? cheapestpath will typically be a pointer into /* XXX is this right? cheapestpath will typically be a pointer into
* pathlist, won't it? * pathlist, won't it?
*/ */
freeObject(node->cheapestpath); freeObject(node->cheapestpath);
freeObject(node->restrictinfo);
freeObject(node->joininfo);
freeObject(node->innerjoin);
pfree(node);
}
/* ----------------
* _freeIndexOptInfo
* ----------------
*/
static void
_freeIndexOptInfo(IndexOptInfo *node)
{
/* ----------------
* free remainder of node
* ----------------
*/
if (node->classlist) if (node->classlist)
pfree(node->classlist); pfree(node->classlist);
...@@ -746,10 +764,6 @@ _freeRelOptInfo(RelOptInfo *node) ...@@ -746,10 +764,6 @@ _freeRelOptInfo(RelOptInfo *node)
freeObject(node->indpred); freeObject(node->indpred);
freeObject(node->restrictinfo);
freeObject(node->joininfo);
freeObject(node->innerjoin);
pfree(node); pfree(node);
} }
...@@ -837,7 +851,6 @@ _freeTidPath(TidPath *node) ...@@ -837,7 +851,6 @@ _freeTidPath(TidPath *node)
static void static void
FreeJoinPathFields(JoinPath *node) FreeJoinPathFields(JoinPath *node)
{ {
freeObject(node->pathinfo);
freeObject(node->outerjoinpath); freeObject(node->outerjoinpath);
freeObject(node->innerjoinpath); freeObject(node->innerjoinpath);
} }
...@@ -936,7 +949,7 @@ _freeRestrictInfo(RestrictInfo *node) ...@@ -936,7 +949,7 @@ _freeRestrictInfo(RestrictInfo *node)
* ---------------- * ----------------
*/ */
freeObject(node->clause); freeObject(node->clause);
/* this is certainly wrong? index RelOptInfos don't belong to /* this is certainly wrong? IndexOptInfos don't belong to
* RestrictInfo... * RestrictInfo...
*/ */
freeObject(node->subclauseindices); freeObject(node->subclauseindices);
...@@ -1253,6 +1266,9 @@ freeObject(void *node) ...@@ -1253,6 +1266,9 @@ freeObject(void *node)
case T_Stream: case T_Stream:
_freeStream(node); _freeStream(node);
break; break;
case T_IndexOptInfo:
_freeIndexOptInfo(node);
break;
/* /*
* PARSE NODES * PARSE NODES
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: outfuncs.c,v 1.100 1999/12/13 01:26:53 tgl Exp $ * $Id: outfuncs.c,v 1.101 2000/01/09 00:26:23 tgl Exp $
* *
* NOTES * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -265,9 +265,9 @@ static void ...@@ -265,9 +265,9 @@ static void
_outPlanInfo(StringInfo str, Plan *node) _outPlanInfo(StringInfo str, Plan *node)
{ {
appendStringInfo(str, appendStringInfo(str,
":cost %g :size %d :width %d :state %s :qptargetlist ", ":cost %g :rows %.0f :width %d :state %s :qptargetlist ",
node->cost, node->cost,
node->plan_size, node->plan_rows,
node->plan_width, node->plan_width,
node->state ? "not-NULL" : "<>"); node->state ? "not-NULL" : "<>");
_outNode(str, node->targetlist); _outNode(str, node->targetlist);
...@@ -834,6 +834,7 @@ _outEState(StringInfo str, EState *node) ...@@ -834,6 +834,7 @@ _outEState(StringInfo str, EState *node)
/* /*
* Stuff from relation.h * Stuff from relation.h
*/ */
static void static void
_outRelOptInfo(StringInfo str, RelOptInfo *node) _outRelOptInfo(StringInfo str, RelOptInfo *node)
{ {
...@@ -841,12 +842,12 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node) ...@@ -841,12 +842,12 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
_outIntList(str, node->relids); _outIntList(str, node->relids);
appendStringInfo(str, appendStringInfo(str,
" :indexed %s :pages %u :tuples %u :size %u :width %u :targetlist ", " :rows %.0f :width %d :indexed %s :pages %ld :tuples %.0f :targetlist ",
node->rows,
node->width,
node->indexed ? "true" : "false", node->indexed ? "true" : "false",
node->pages, node->pages,
node->tuples, node->tuples);
node->size,
node->width);
_outNode(str, node->targetlist); _outNode(str, node->targetlist);
appendStringInfo(str, " :pathlist "); appendStringInfo(str, " :pathlist ");
...@@ -871,6 +872,15 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node) ...@@ -871,6 +872,15 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
_outNode(str, node->innerjoin); _outNode(str, node->innerjoin);
} }
static void
_outIndexOptInfo(StringInfo str, IndexOptInfo *node)
{
appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
node->indexoid,
node->pages,
node->tuples);
}
/* /*
* TargetEntry is a subclass of Node. * TargetEntry is a subclass of Node.
*/ */
...@@ -910,7 +920,7 @@ _outRowMark(StringInfo str, RowMark *node) ...@@ -910,7 +920,7 @@ _outRowMark(StringInfo str, RowMark *node)
static void static void
_outPath(StringInfo str, Path *node) _outPath(StringInfo str, Path *node)
{ {
appendStringInfo(str, " PATH :pathtype %d :cost %f :pathkeys ", appendStringInfo(str, " PATH :pathtype %d :cost %.2f :pathkeys ",
node->pathtype, node->pathtype,
node->path_cost); node->path_cost);
_outNode(str, node->pathkeys); _outNode(str, node->pathkeys);
...@@ -923,7 +933,7 @@ static void ...@@ -923,7 +933,7 @@ static void
_outIndexPath(StringInfo str, IndexPath *node) _outIndexPath(StringInfo str, IndexPath *node)
{ {
appendStringInfo(str, appendStringInfo(str,
" INDEXPATH :pathtype %d :cost %f :pathkeys ", " INDEXPATH :pathtype %d :cost %.2f :pathkeys ",
node->path.pathtype, node->path.pathtype,
node->path.path_cost); node->path.path_cost);
_outNode(str, node->path.pathkeys); _outNode(str, node->path.pathkeys);
...@@ -945,7 +955,7 @@ static void ...@@ -945,7 +955,7 @@ static void
_outTidPath(StringInfo str, TidPath *node) _outTidPath(StringInfo str, TidPath *node)
{ {
appendStringInfo(str, appendStringInfo(str,
" TIDPATH :pathtype %d :cost %f :pathkeys ", " TIDPATH :pathtype %d :cost %.2f :pathkeys ",
node->path.pathtype, node->path.pathtype,
node->path.path_cost); node->path.path_cost);
_outNode(str, node->path.pathkeys); _outNode(str, node->path.pathkeys);
...@@ -964,14 +974,11 @@ static void ...@@ -964,14 +974,11 @@ static void
_outNestPath(StringInfo str, NestPath *node) _outNestPath(StringInfo str, NestPath *node)
{ {
appendStringInfo(str, appendStringInfo(str,
" NESTPATH :pathtype %d :cost %f :pathkeys ", " NESTPATH :pathtype %d :cost %.2f :pathkeys ",
node->path.pathtype, node->path.pathtype,
node->path.path_cost); node->path.path_cost);
_outNode(str, node->path.pathkeys); _outNode(str, node->path.pathkeys);
appendStringInfo(str, " :pathinfo ");
_outNode(str, node->pathinfo);
/* /*
* Not sure if these are nodes; they're declared as "struct path *". * Not sure if these are nodes; they're declared as "struct path *".
* For now, i'll just print the addresses. * For now, i'll just print the addresses.
...@@ -990,14 +997,11 @@ static void ...@@ -990,14 +997,11 @@ static void
_outMergePath(StringInfo str, MergePath *node) _outMergePath(StringInfo str, MergePath *node)
{ {
appendStringInfo(str, appendStringInfo(str,
" MERGEPATH :pathtype %d :cost %f :pathkeys ", " MERGEPATH :pathtype %d :cost %.2f :pathkeys ",
node->jpath.path.pathtype, node->jpath.path.pathtype,
node->jpath.path.path_cost); node->jpath.path.path_cost);
_outNode(str, node->jpath.path.pathkeys); _outNode(str, node->jpath.path.pathkeys);
appendStringInfo(str, " :pathinfo ");
_outNode(str, node->jpath.pathinfo);
/* /*
* Not sure if these are nodes; they're declared as "struct path *". * Not sure if these are nodes; they're declared as "struct path *".
* For now, i'll just print the addresses. * For now, i'll just print the addresses.
...@@ -1025,14 +1029,11 @@ static void ...@@ -1025,14 +1029,11 @@ static void
_outHashPath(StringInfo str, HashPath *node) _outHashPath(StringInfo str, HashPath *node)
{ {
appendStringInfo(str, appendStringInfo(str,
" HASHPATH :pathtype %d :cost %f :pathkeys ", " HASHPATH :pathtype %d :cost %.2f :pathkeys ",
node->jpath.path.pathtype, node->jpath.path.pathtype,
node->jpath.path.path_cost); node->jpath.path.path_cost);
_outNode(str, node->jpath.path.pathkeys); _outNode(str, node->jpath.path.pathkeys);
appendStringInfo(str, " :pathinfo ");
_outNode(str, node->jpath.pathinfo);
/* /*
* Not sure if these are nodes; they're declared as "struct path *". * Not sure if these are nodes; they're declared as "struct path *".
* For now, i'll just print the addresses. * For now, i'll just print the addresses.
...@@ -1067,9 +1068,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) ...@@ -1067,9 +1068,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
appendStringInfo(str, " RESTRICTINFO :clause "); appendStringInfo(str, " RESTRICTINFO :clause ");
_outNode(str, node->clause); _outNode(str, node->clause);
appendStringInfo(str, appendStringInfo(str, " :subclauseindices ");
" :selectivity %f :subclauseindices ",
node->selectivity);
_outNode(str, node->subclauseindices); _outNode(str, node->subclauseindices);
appendStringInfo(str, " :mergejoinoperator %u ", node->mergejoinoperator); appendStringInfo(str, " :mergejoinoperator %u ", node->mergejoinoperator);
...@@ -1466,6 +1465,9 @@ _outNode(StringInfo str, void *obj) ...@@ -1466,6 +1465,9 @@ _outNode(StringInfo str, void *obj)
case T_RelOptInfo: case T_RelOptInfo:
_outRelOptInfo(str, obj); _outRelOptInfo(str, obj);
break; break;
case T_IndexOptInfo:
_outIndexOptInfo(str, obj);
break;
case T_TargetEntry: case T_TargetEntry:
_outTargetEntry(str, obj); _outTargetEntry(str, obj);
break; break;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.33 1999/11/23 20:06:53 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.34 2000/01/09 00:26:24 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -364,8 +364,8 @@ print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label) ...@@ -364,8 +364,8 @@ print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
return; return;
for (i = 0; i < indentLevel; i++) for (i = 0; i < indentLevel; i++)
printf(" "); printf(" ");
printf("%s%s :c=%.4f :s=%d :w=%d ", label, plannode_type(p), printf("%s%s :c=%.4f :r=%.0f :w=%d ", label, plannode_type(p),
p->cost, p->plan_size, p->plan_width); p->cost, p->plan_rows, p->plan_width);
if (IsA(p, Scan) ||IsA(p, SeqScan)) if (IsA(p, Scan) ||IsA(p, SeqScan))
{ {
RangeTblEntry *rte; RangeTblEntry *rte;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.76 1999/12/13 01:26:54 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.77 2000/01/09 00:26:24 tgl Exp $
* *
* NOTES * NOTES
* Most of the read functions for plan nodes are tested. (In fact, they * Most of the read functions for plan nodes are tested. (In fact, they
...@@ -233,9 +233,9 @@ _getPlan(Plan *node) ...@@ -233,9 +233,9 @@ _getPlan(Plan *node)
token = lsptok(NULL, &length); /* next is the actual cost */ token = lsptok(NULL, &length); /* next is the actual cost */
node->cost = (Cost) atof(token); node->cost = (Cost) atof(token);
token = lsptok(NULL, &length); /* skip the :size */ token = lsptok(NULL, &length); /* skip the :rows */
token = lsptok(NULL, &length); /* get the plan_size */ token = lsptok(NULL, &length); /* get the plan_rows */
node->plan_size = atoi(token); node->plan_rows = atof(token);
token = lsptok(NULL, &length); /* skip the :width */ token = lsptok(NULL, &length); /* skip the :width */
token = lsptok(NULL, &length); /* get the plan_width */ token = lsptok(NULL, &length); /* get the plan_width */
...@@ -1293,6 +1293,14 @@ _readRelOptInfo() ...@@ -1293,6 +1293,14 @@ _readRelOptInfo()
token = lsptok(NULL, &length); /* get :relids */ token = lsptok(NULL, &length); /* get :relids */
local_node->relids = toIntList(nodeRead(true)); /* now read it */ local_node->relids = toIntList(nodeRead(true)); /* now read it */
token = lsptok(NULL, &length); /* get :rows */
token = lsptok(NULL, &length); /* now read it */
local_node->rows = atof(token);
token = lsptok(NULL, &length); /* get :width */
token = lsptok(NULL, &length); /* now read it */
local_node->width = atoi(token);
token = lsptok(NULL, &length); /* get :indexed */ token = lsptok(NULL, &length); /* get :indexed */
token = lsptok(NULL, &length); /* now read it */ token = lsptok(NULL, &length); /* now read it */
...@@ -1303,19 +1311,11 @@ _readRelOptInfo() ...@@ -1303,19 +1311,11 @@ _readRelOptInfo()
token = lsptok(NULL, &length); /* get :pages */ token = lsptok(NULL, &length); /* get :pages */
token = lsptok(NULL, &length); /* now read it */ token = lsptok(NULL, &length); /* now read it */
local_node->pages = (unsigned int) atoi(token); local_node->pages = atol(token);
token = lsptok(NULL, &length); /* get :tuples */ token = lsptok(NULL, &length); /* get :tuples */
token = lsptok(NULL, &length); /* now read it */ token = lsptok(NULL, &length); /* now read it */
local_node->tuples = (unsigned int) atoi(token); local_node->tuples = atof(token);
token = lsptok(NULL, &length); /* get :size */
token = lsptok(NULL, &length); /* now read it */
local_node->size = (unsigned int) atoi(token);
token = lsptok(NULL, &length); /* get :width */
token = lsptok(NULL, &length); /* now read it */
local_node->width = (unsigned int) atoi(token);
token = lsptok(NULL, &length); /* get :targetlist */ token = lsptok(NULL, &length); /* get :targetlist */
local_node->targetlist = nodeRead(true); /* now read it */ local_node->targetlist = nodeRead(true); /* now read it */
...@@ -1348,6 +1348,34 @@ _readRelOptInfo() ...@@ -1348,6 +1348,34 @@ _readRelOptInfo()
return local_node; return local_node;
} }
/* ----------------
* _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 * _readTargetEntry
* ---------------- * ----------------
...@@ -1572,9 +1600,6 @@ _readNestPath() ...@@ -1572,9 +1600,6 @@ _readNestPath()
token = lsptok(NULL, &length); /* get :pathkeys */ token = lsptok(NULL, &length); /* get :pathkeys */
local_node->path.pathkeys = nodeRead(true); /* now read it */ local_node->path.pathkeys = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :pathinfo */
local_node->pathinfo = nodeRead(true); /* now read it */
/* /*
* Not sure if these are nodes; they're declared as "struct path *". * Not sure if these are nodes; they're declared as "struct path *".
* For now, i'll just print the addresses. * For now, i'll just print the addresses.
...@@ -1626,9 +1651,6 @@ _readMergePath() ...@@ -1626,9 +1651,6 @@ _readMergePath()
token = lsptok(NULL, &length); /* get :pathkeys */ token = lsptok(NULL, &length); /* get :pathkeys */
local_node->jpath.path.pathkeys = nodeRead(true); /* now read it */ local_node->jpath.path.pathkeys = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :pathinfo */
local_node->jpath.pathinfo = nodeRead(true); /* now read it */
/* /*
* Not sure if these are nodes; they're declared as "struct path *". * Not sure if these are nodes; they're declared as "struct path *".
* For now, i'll just print the addresses. * For now, i'll just print the addresses.
...@@ -1689,9 +1711,6 @@ _readHashPath() ...@@ -1689,9 +1711,6 @@ _readHashPath()
token = lsptok(NULL, &length); /* get :pathkeys */ token = lsptok(NULL, &length); /* get :pathkeys */
local_node->jpath.path.pathkeys = nodeRead(true); /* now read it */ local_node->jpath.path.pathkeys = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :pathinfo */
local_node->jpath.pathinfo = nodeRead(true); /* now read it */
/* /*
* Not sure if these are nodes; they're declared as "struct path *". * Not sure if these are nodes; they're declared as "struct path *".
* For now, i'll just print the addresses. * For now, i'll just print the addresses.
...@@ -1762,10 +1781,6 @@ _readRestrictInfo() ...@@ -1762,10 +1781,6 @@ _readRestrictInfo()
token = lsptok(NULL, &length); /* get :clause */ token = lsptok(NULL, &length); /* get :clause */
local_node->clause = nodeRead(true); /* now read it */ local_node->clause = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :selectivity */
token = lsptok(NULL, &length); /* now read it */
local_node->selectivity = atof(token);
token = lsptok(NULL, &length); /* get :subclauseindices */ token = lsptok(NULL, &length); /* get :subclauseindices */
local_node->subclauseindices = nodeRead(true); /* now read it */ local_node->subclauseindices = nodeRead(true); /* now read it */
...@@ -1909,6 +1924,8 @@ parsePlanString(void) ...@@ -1909,6 +1924,8 @@ parsePlanString(void)
return_value = _readEState(); return_value = _readEState();
else if (!strncmp(token, "RELOPTINFO", length)) else if (!strncmp(token, "RELOPTINFO", length))
return_value = _readRelOptInfo(); return_value = _readRelOptInfo();
else if (!strncmp(token, "INDEXOPTINFO", length))
return_value = _readIndexOptInfo();
else if (!strncmp(token, "TARGETENTRY", length)) else if (!strncmp(token, "TARGETENTRY", length))
return_value = _readTargetEntry(); return_value = _readTargetEntry();
else if (!strncmp(token, "RTE", length)) else if (!strncmp(token, "RTE", length))
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: geqo_eval.c,v 1.44 1999/09/21 20:58:08 momjian Exp $ * $Id: geqo_eval.c,v 1.45 2000/01/09 00:26:27 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -95,7 +95,7 @@ geqo_eval(Query *root, Gene *tour, int num_gene) ...@@ -95,7 +95,7 @@ geqo_eval(Query *root, Gene *tour, int num_gene)
joinrel = gimme_tree(root, tour, 0, num_gene, NULL); joinrel = gimme_tree(root, tour, 0, num_gene, NULL);
/* compute fitness */ /* compute fitness */
fitness = (Cost) joinrel->cheapestpath->path_cost; fitness = joinrel->cheapestpath->path_cost;
/* restore join_rel_list */ /* restore join_rel_list */
root->join_rel_list = savelist; root->join_rel_list = savelist;
...@@ -177,16 +177,14 @@ gimme_tree(Query *root, Gene *tour, int rel_count, int num_gene, RelOptInfo *old ...@@ -177,16 +177,14 @@ gimme_tree(Query *root, Gene *tour, int rel_count, int num_gene, RelOptInfo *old
elog(DEBUG, "gimme_tree: still %d relations left", length(new_rels)); elog(DEBUG, "gimme_tree: still %d relations left", length(new_rels));
} }
rels_set_cheapest(new_rels); rels_set_cheapest(root, new_rels);
/* get essential new relation */ /* get essential new relation */
new_rel = (RelOptInfo *) lfirst(new_rels); new_rel = (RelOptInfo *) lfirst(new_rels);
rel_count++; rel_count++;
/* processing of other new_rel attributes */ /* processing of other new_rel attributes */
if (new_rel->size <= 0) set_rel_rows_width(root, new_rel);
new_rel->size = compute_rel_size(new_rel);
new_rel->width = compute_rel_width(new_rel);
root->join_rel_list = lcons(new_rel, NIL); root->join_rel_list = lcons(new_rel, NIL);
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: geqo_misc.c,v 1.24 1999/08/16 02:17:48 tgl Exp $ * $Id: geqo_misc.c,v 1.25 2000/01/09 00:26:27 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -177,10 +177,9 @@ geqo_print_path(Query *root, Path *path, int indent) ...@@ -177,10 +177,9 @@ geqo_print_path(Query *root, Path *path, int indent)
} }
if (join) if (join)
{ {
int size = path->parent->size;
jp = (JoinPath *) path; jp = (JoinPath *) path;
printf("%s size=%d cost=%f\n", ptype, size, path->path_cost); printf("%s rows=%.0f cost=%f\n",
ptype, path->parent->rows, path->path_cost);
switch (nodeTag(path)) switch (nodeTag(path))
{ {
case T_MergePath: case T_MergePath:
...@@ -188,7 +187,7 @@ geqo_print_path(Query *root, Path *path, int indent) ...@@ -188,7 +187,7 @@ geqo_print_path(Query *root, Path *path, int indent)
for (i = 0; i < indent + 1; i++) for (i = 0; i < indent + 1; i++)
printf("\t"); printf("\t");
printf(" clauses=("); printf(" clauses=(");
geqo_print_joinclauses(root, ((JoinPath *) path)->pathinfo); geqo_print_joinclauses(root, path->parent->restrictinfo);
printf(")\n"); printf(")\n");
if (nodeTag(path) == T_MergePath) if (nodeTag(path) == T_MergePath)
...@@ -213,11 +212,10 @@ geqo_print_path(Query *root, Path *path, int indent) ...@@ -213,11 +212,10 @@ geqo_print_path(Query *root, Path *path, int indent)
} }
else else
{ {
int size = path->parent->size;
int relid = lfirsti(path->parent->relids); int relid = lfirsti(path->parent->relids);
printf("%s(%d) size=%d cost=%f\n", printf("%s(%d) rows=%.0f cost=%f\n",
ptype, relid, size, path->path_cost); ptype, relid, path->parent->rows, path->path_cost);
if (IsA(path, IndexPath)) if (IsA(path, IndexPath))
{ {
...@@ -236,7 +234,7 @@ geqo_print_rel(Query *root, RelOptInfo *rel) ...@@ -236,7 +234,7 @@ geqo_print_rel(Query *root, RelOptInfo *rel)
printf("("); printf("(");
foreach(l, rel->relids) foreach(l, rel->relids)
printf("%d ", lfirsti(l)); printf("%d ", lfirsti(l));
printf("): size=%d width=%d\n", rel->size, rel->width); printf("): rows=%.0f width=%d\n", rel->rows, rel->width);
printf("\tpath list:\n"); printf("\tpath list:\n");
foreach(l, rel->pathlist) foreach(l, rel->pathlist)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.54 1999/11/23 20:06:54 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.55 2000/01/09 00:26:29 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -66,23 +66,16 @@ make_one_rel(Query *root, List *rels) ...@@ -66,23 +66,16 @@ make_one_rel(Query *root, List *rels)
if (levels_needed <= 1) if (levels_needed <= 1)
{ {
/* /*
* Unsorted single relation, no more processing is required. * Single relation, no more processing is required.
*/ */
return lfirst(rels); return lfirst(rels);
} }
else else
{ {
/* /*
* This means that joins or sorts are required. Set selectivities * Generate join tree.
* of any clauses not yet set. (I think that this is redundant;
* set_base_rel_pathlist should have set them all already. But
* a scan to check that they are all set doesn't cost much...)
*/ */
set_rest_relselec(root, rels);
return make_one_rel_by_joins(root, rels, levels_needed); return make_one_rel_by_joins(root, rels, levels_needed);
} }
} }
...@@ -115,7 +108,7 @@ set_base_rel_pathlist(Query *root, List *rels) ...@@ -115,7 +108,7 @@ set_base_rel_pathlist(Query *root, List *rels)
tidscan_pathlist = create_tidscan_paths(root, rel); tidscan_pathlist = create_tidscan_paths(root, rel);
if (tidscan_pathlist) if (tidscan_pathlist)
sequential_scan_list = nconc(sequential_scan_list, sequential_scan_list = nconc(sequential_scan_list,
tidscan_pathlist); tidscan_pathlist);
rel_index_scan_list = create_index_paths(root, rel_index_scan_list = create_index_paths(root,
rel, rel,
indices, indices,
...@@ -126,7 +119,6 @@ set_base_rel_pathlist(Query *root, List *rels) ...@@ -126,7 +119,6 @@ set_base_rel_pathlist(Query *root, List *rels)
* to have marked OR restriction clauses with relevant indices; * to have marked OR restriction clauses with relevant indices;
* this is why it doesn't need to be given the full list of indices. * this is why it doesn't need to be given the full list of indices.
*/ */
or_index_scan_list = create_or_index_paths(root, rel, or_index_scan_list = create_or_index_paths(root, rel,
rel->restrictinfo); rel->restrictinfo);
...@@ -139,19 +131,10 @@ set_base_rel_pathlist(Query *root, List *rels) ...@@ -139,19 +131,10 @@ set_base_rel_pathlist(Query *root, List *rels)
nconc(rel_index_scan_list, nconc(rel_index_scan_list,
or_index_scan_list)); or_index_scan_list));
/* Now find the cheapest of the paths */
set_cheapest(rel, rel->pathlist); set_cheapest(rel, rel->pathlist);
/* Mark rel with estimated output rows and width */
/* Set the selectivity estimates for any restriction clauses that set_rel_rows_width(root, rel);
* didn't get set as a byproduct of index-path selectivity estimation
* (see create_index_path()).
*/
set_rest_selec(root, rel->restrictinfo);
/* Calculate the estimated size (post-restrictions) and tuple width
* for this base rel. This uses the restriction clause selectivities.
*/
rel->size = compute_rel_size(rel);
rel->width = compute_rel_width(rel);
} }
} }
...@@ -217,16 +200,12 @@ make_one_rel_by_joins(Query *root, List *rels, int levels_needed) ...@@ -217,16 +200,12 @@ make_one_rel_by_joins(Query *root, List *rels, int levels_needed)
xfunc_trypullup((RelOptInfo *) lfirst(x)); xfunc_trypullup((RelOptInfo *) lfirst(x));
#endif #endif
rels_set_cheapest(joined_rels); rels_set_cheapest(root, joined_rels);
foreach(x, joined_rels) foreach(x, joined_rels)
{ {
rel = (RelOptInfo *) lfirst(x); rel = (RelOptInfo *) lfirst(x);
if (rel->size <= 0)
rel->size = compute_rel_size(rel);
rel->width = compute_rel_width(rel);
#ifdef OPTIMIZER_DEBUG #ifdef OPTIMIZER_DEBUG
printf("levels left: %d\n", levels_needed); printf("levels left: %d\n", levels_needed);
debug_print_rel(root, rel); debug_print_rel(root, rel);
...@@ -297,10 +276,9 @@ print_path(Query *root, Path *path, int indent) ...@@ -297,10 +276,9 @@ print_path(Query *root, Path *path, int indent)
} }
if (join) if (join)
{ {
int size = path->parent->size;
jp = (JoinPath *) path; jp = (JoinPath *) path;
printf("%s size=%d cost=%f\n", ptype, size, path->path_cost); printf("%s rows=%.0f cost=%f\n",
ptype, path->parent->rows, path->path_cost);
switch (nodeTag(path)) switch (nodeTag(path))
{ {
case T_MergePath: case T_MergePath:
...@@ -308,7 +286,7 @@ print_path(Query *root, Path *path, int indent) ...@@ -308,7 +286,7 @@ print_path(Query *root, Path *path, int indent)
for (i = 0; i < indent + 1; i++) for (i = 0; i < indent + 1; i++)
printf("\t"); printf("\t");
printf(" clauses=("); printf(" clauses=(");
print_joinclauses(root, ((JoinPath *) path)->pathinfo); print_joinclauses(root, jp->path.parent->restrictinfo);
printf(")\n"); printf(")\n");
if (nodeTag(path) == T_MergePath) if (nodeTag(path) == T_MergePath)
...@@ -333,11 +311,10 @@ print_path(Query *root, Path *path, int indent) ...@@ -333,11 +311,10 @@ print_path(Query *root, Path *path, int indent)
} }
else else
{ {
int size = path->parent->size;
int relid = lfirsti(path->parent->relids); int relid = lfirsti(path->parent->relids);
printf("%s(%d) size=%d cost=%f\n", printf("%s(%d) rows=%.0f cost=%f\n",
ptype, relid, size, path->path_cost); ptype, relid, path->parent->rows, path->path_cost);
if (IsA(path, IndexPath)) if (IsA(path, IndexPath))
{ {
...@@ -355,7 +332,7 @@ debug_print_rel(Query *root, RelOptInfo *rel) ...@@ -355,7 +332,7 @@ debug_print_rel(Query *root, RelOptInfo *rel)
printf("("); printf("(");
foreach(l, rel->relids) foreach(l, rel->relids)
printf("%d ", lfirsti(l)); printf("%d ", lfirsti(l));
printf("): size=%d width=%d\n", rel->size, rel->width); printf("): rows=%.0f width=%d\n", rel->rows, rel->width);
printf("\tpath list:\n"); printf("\tpath list:\n");
foreach(l, rel->pathlist) foreach(l, rel->pathlist)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.26 1999/09/09 02:35:47 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.27 2000/01/09 00:26:31 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,102 +24,58 @@ ...@@ -24,102 +24,58 @@
/**************************************************************************** /****************************************************************************
* ROUTINES TO SET CLAUSE SELECTIVITIES * ROUTINES TO COMPUTE SELECTIVITIES
****************************************************************************/ ****************************************************************************/
/* /*
* set_clause_selectivities - * restrictlist_selec -
* Sets the selectivity field for each clause in 'restrictinfo-list' * Compute the selectivity of an implicitly-ANDed list of RestrictInfo
* to 'new-selectivity'. If the selectivity has already been set, * clauses.
* change it only if the new one is better.
*/
void
set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity)
{
List *rlist;
foreach(rlist, restrictinfo_list)
{
RestrictInfo *clausenode = (RestrictInfo *) lfirst(rlist);
Cost cost_clause = clausenode->selectivity;
if (cost_clause <= 0 || new_selectivity < cost_clause)
clausenode->selectivity = new_selectivity;
}
}
/*
* product_selec -
* Multiplies the selectivities of each clause in 'restrictinfo-list'.
* *
* Returns a flonum corresponding to the selectivity of 'restrictinfo-list'. * This is the same as clauselist_selec except for the form of the input.
*/ */
Cost Selectivity
product_selec(List *restrictinfo_list) restrictlist_selec(Query *root, List *restrictinfo_list)
{ {
Cost result = (Cost) 1.0; List *clauselist = get_actual_clauses(restrictinfo_list);
List *rlist; Selectivity result;
foreach(rlist, restrictinfo_list) result = clauselist_selec(root, clauselist);
{ freeList(clauselist);
result *= ((RestrictInfo *) lfirst(rlist))->selectivity;
}
return result; return result;
} }
/* /*
* set_rest_relselec - * clauselist_selec -
* Scans through clauses on each relation and assigns a selectivity to * Compute the selectivity of an implicitly-ANDed list of boolean
* those clauses that haven't been assigned a selectivity by an index. * expression clauses.
*
* MODIFIES: selectivities of the various rel's restrictinfo slots.
*/ */
void Selectivity
set_rest_relselec(Query *root, List *rel_list) clauselist_selec(Query *root, List *clauses)
{ {
List *x; Selectivity s1 = 1.0;
List *clause;
foreach(x, rel_list)
/* Use the product of the selectivities of the subclauses.
* XXX this is probably too optimistic, since the subclauses
* are very likely not independent...
*/
foreach(clause, clauses)
{ {
RelOptInfo *rel = (RelOptInfo *) lfirst(x); Selectivity s2 = compute_clause_selec(root, (Node *) lfirst(clause));
set_rest_selec(root, rel->restrictinfo); s1 = s1 * s2;
}
}
/*
* set_rest_selec -
* Sets the selectivity fields for those clauses within a single
* relation's 'restrictinfo-list' that haven't already been set.
*/
void
set_rest_selec(Query *root, List *restrictinfo_list)
{
List *rlist;
foreach(rlist, restrictinfo_list)
{
RestrictInfo *clause = (RestrictInfo *) lfirst(rlist);
if (clause->selectivity <= 0)
{
clause->selectivity =
compute_clause_selec(root, (Node *) clause->clause);
}
} }
return s1;
} }
/****************************************************************************
* ROUTINES TO COMPUTE SELECTIVITIES
****************************************************************************/
/* /*
* compute_clause_selec - * compute_clause_selec -
* Computes the selectivity of a clause. * Compute the selectivity of a general boolean expression clause.
*/ */
Cost Selectivity
compute_clause_selec(Query *root, Node *clause) compute_clause_selec(Query *root, Node *clause)
{ {
Cost s1 = 1.0; /* default for any unhandled clause type */ Selectivity s1 = 1.0; /* default for any unhandled clause type */
if (clause == NULL) if (clause == NULL)
return s1; return s1;
...@@ -131,17 +87,12 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -131,17 +87,12 @@ compute_clause_selec(Query *root, Node *clause)
* is what we have. The magic #define constants are a hack. I * is what we have. The magic #define constants are a hack. I
* didn't want to have to do system cache look ups to find out all * didn't want to have to do system cache look ups to find out all
* of that info. * of that info.
*
* XXX why are we using varno and varoattno? Seems like it should
* be varno/varattno or varnoold/varoattno, not mix & match...
*/ */
Oid relid = getrelid(((Var *) clause)->varno,
root->rtable);
s1 = restriction_selectivity(F_EQSEL, s1 = restriction_selectivity(F_EQSEL,
BooleanEqualOperator, BooleanEqualOperator,
relid, getrelid(((Var *) clause)->varno,
((Var *) clause)->varoattno, root->rtable),
((Var *) clause)->varattno,
Int8GetDatum(true), Int8GetDatum(true),
SEL_CONSTANT | SEL_RIGHT); SEL_CONSTANT | SEL_RIGHT);
} }
...@@ -163,21 +114,12 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -163,21 +114,12 @@ compute_clause_selec(Query *root, Node *clause)
} }
else if (and_clause(clause)) else if (and_clause(clause))
{ {
/* Use the product of the selectivities of the subclauses. s1 = clauselist_selec(root, ((Expr *) clause)->args);
* XXX this is probably too optimistic, since the subclauses
* are very likely not independent...
*/
List *arg;
s1 = 1.0;
foreach(arg, ((Expr *) clause)->args)
{
Cost s2 = compute_clause_selec(root, (Node *) lfirst(arg));
s1 = s1 * s2;
}
} }
else if (or_clause(clause)) else if (or_clause(clause))
{ {
/* Selectivities for an 'or' clause are computed as s1+s2 - s1*s2 /*
* Selectivities for an 'or' clause are computed as s1+s2 - s1*s2
* to account for the probable overlap of selected tuple sets. * to account for the probable overlap of selected tuple sets.
* XXX is this too conservative? * XXX is this too conservative?
*/ */
...@@ -185,31 +127,15 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -185,31 +127,15 @@ compute_clause_selec(Query *root, Node *clause)
s1 = 0.0; s1 = 0.0;
foreach(arg, ((Expr *) clause)->args) foreach(arg, ((Expr *) clause)->args)
{ {
Cost s2 = compute_clause_selec(root, (Node *) lfirst(arg)); Selectivity s2 = compute_clause_selec(root, (Node *) lfirst(arg));
s1 = s1 + s2 - s1 * s2; s1 = s1 + s2 - s1 * s2;
} }
} }
else if (is_funcclause(clause))
{
/*
* This is not an operator, so we guess at the selectivity. THIS
* IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE ABLE TO HAVE
* SELECTIVITIES THEMSELVES. -- JMH 7/9/92
*/
s1 = (Cost) 0.3333333;
}
else if (is_subplan(clause))
{
/*
* Just for the moment! FIX ME! - vadim 02/04/98
*/
s1 = 1.0;
}
else if (is_opclause(clause)) else if (is_opclause(clause))
{ {
if (NumRelids(clause) == 1) if (NumRelids(clause) == 1)
{ {
/* The clause is not a join clause, since there is only one /* The opclause is not a join clause, since there is only one
* relid in the clause. The clause selectivity will be based on * relid in the clause. The clause selectivity will be based on
* the operator selectivity and operand values. * the operator selectivity and operand values.
*/ */
...@@ -221,33 +147,20 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -221,33 +147,20 @@ compute_clause_selec(Query *root, Node *clause)
* selectivity of 0.5 * selectivity of 0.5
*/ */
if (!oprrest) if (!oprrest)
s1 = (Cost) 0.5; s1 = (Selectivity) 0.5;
else else
{ {
int relidx; int relidx;
AttrNumber attno; AttrNumber attno;
Datum constval; Datum constval;
int flag; int flag;
Oid reloid;
get_relattval(clause, 0, &relidx, &attno, &constval, &flag); get_relattval(clause, 0, &relidx, &attno, &constval, &flag);
if (relidx && attno) reloid = relidx ? getrelid(relidx, root->rtable) : InvalidOid;
s1 = (Cost) restriction_selectivity(oprrest, s1 = restriction_selectivity(oprrest, opno,
opno, reloid, attno,
getrelid(relidx, constval, flag);
root->rtable),
attno,
constval,
flag);
else
{
/*
* attno can be 0 if the clause had a function in it,
* i.e. WHERE myFunc(f) = 10
*
* XXX should be FIXED to use function selectivity
*/
s1 = (Cost) (0.5);
}
} }
} }
else else
...@@ -265,30 +178,41 @@ compute_clause_selec(Query *root, Node *clause) ...@@ -265,30 +178,41 @@ compute_clause_selec(Query *root, Node *clause)
* selectivity of 0.5 * selectivity of 0.5
*/ */
if (!oprjoin) if (!oprjoin)
s1 = (Cost) (0.5); s1 = (Selectivity) 0.5;
else else
{ {
int relid1, int relid1,
relid2; relid2;
AttrNumber attno1, AttrNumber attno1,
attno2; attno2;
Oid reloid1,
reloid2;
get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2); get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
if (relid1 && relid2 && attno1 && attno2) reloid1 = relid1 ? getrelid(relid1, root->rtable) : InvalidOid;
reloid2 = relid2 ? getrelid(relid2, root->rtable) : InvalidOid;
s1 = (Cost) join_selectivity(oprjoin, s1 = join_selectivity(oprjoin, opno,
opno, reloid1, attno1,
getrelid(relid1, reloid2, attno2);
root->rtable),
attno1,
getrelid(relid2,
root->rtable),
attno2);
else /* XXX more code for function selectivity? */
s1 = (Cost) (0.5);
} }
} }
} }
else if (is_funcclause(clause))
{
/*
* This is not an operator, so we guess at the selectivity. THIS
* IS A HACK TO GET V4 OUT THE DOOR. FUNCS SHOULD BE ABLE TO HAVE
* SELECTIVITIES THEMSELVES. -- JMH 7/9/92
*/
s1 = (Selectivity) 0.3333333;
}
else if (is_subplan(clause))
{
/*
* Just for the moment! FIX ME! - vadim 02/04/98
*/
s1 = 1.0;
}
return s1; return s1;
} }
This diff is collapsed.
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.46 1999/08/21 03:49:00 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.47 2000/01/09 00:26:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -40,7 +40,7 @@ static List *match_unsorted_inner(RelOptInfo *joinrel, RelOptInfo *outerrel, ...@@ -40,7 +40,7 @@ static List *match_unsorted_inner(RelOptInfo *joinrel, RelOptInfo *outerrel,
List *mergeclause_list); List *mergeclause_list);
static List *hash_inner_and_outer(Query *root, RelOptInfo *joinrel, static List *hash_inner_and_outer(Query *root, RelOptInfo *joinrel,
RelOptInfo *outerrel, RelOptInfo *innerrel); RelOptInfo *outerrel, RelOptInfo *innerrel);
static Cost estimate_disbursion(Query *root, Var *var); static Selectivity estimate_disbursion(Query *root, Var *var);
static List *select_mergejoin_clauses(List *restrictinfo_list); static List *select_mergejoin_clauses(List *restrictinfo_list);
/* /*
...@@ -258,12 +258,8 @@ sort_inner_and_outer(RelOptInfo *joinrel, ...@@ -258,12 +258,8 @@ sort_inner_and_outer(RelOptInfo *joinrel,
curclause_list); curclause_list);
/* And now we can make the path. */ /* And now we can make the path. */
path_node = create_mergejoin_path(joinrel, path_node = create_mergejoin_path(joinrel,
outerrel->size, outerrel->cheapestpath,
innerrel->size, innerrel->cheapestpath,
outerrel->width,
innerrel->width,
(Path *) outerrel->cheapestpath,
(Path *) innerrel->cheapestpath,
merge_pathkeys, merge_pathkeys,
get_actual_clauses(curclause_list), get_actual_clauses(curclause_list),
outerkeys, outerkeys,
...@@ -359,7 +355,6 @@ match_unsorted_outer(RelOptInfo *joinrel, ...@@ -359,7 +355,6 @@ match_unsorted_outer(RelOptInfo *joinrel,
/* Always consider a nestloop join with this outer and best inner. */ /* Always consider a nestloop join with this outer and best inner. */
path_list = lappend(path_list, path_list = lappend(path_list,
create_nestloop_path(joinrel, create_nestloop_path(joinrel,
outerrel,
outerpath, outerpath,
nestinnerpath, nestinnerpath,
merge_pathkeys)); merge_pathkeys));
...@@ -393,7 +388,7 @@ match_unsorted_outer(RelOptInfo *joinrel, ...@@ -393,7 +388,7 @@ match_unsorted_outer(RelOptInfo *joinrel,
int clausecount; int clausecount;
cheapest_cost = cheapest_inner->path_cost + cheapest_cost = cheapest_inner->path_cost +
cost_sort(innersortkeys, innerrel->size, innerrel->width); cost_sort(innersortkeys, innerrel->rows, innerrel->width);
for (clausecount = mergeclausecount; for (clausecount = mergeclausecount;
clausecount > 0; clausecount > 0;
...@@ -427,10 +422,6 @@ match_unsorted_outer(RelOptInfo *joinrel, ...@@ -427,10 +422,6 @@ match_unsorted_outer(RelOptInfo *joinrel,
get_actual_clauses(mergeclauses)); get_actual_clauses(mergeclauses));
path_list = lappend(path_list, path_list = lappend(path_list,
create_mergejoin_path(joinrel, create_mergejoin_path(joinrel,
outerrel->size,
innerrel->size,
outerrel->width,
innerrel->width,
outerpath, outerpath,
mergeinnerpath, mergeinnerpath,
merge_pathkeys, merge_pathkeys,
...@@ -496,7 +487,7 @@ match_unsorted_inner(RelOptInfo *joinrel, ...@@ -496,7 +487,7 @@ match_unsorted_inner(RelOptInfo *joinrel,
if (mergeouterpath != NULL && if (mergeouterpath != NULL &&
mergeouterpath->path_cost <= mergeouterpath->path_cost <=
(outerrel->cheapestpath->path_cost + (outerrel->cheapestpath->path_cost +
cost_sort(outersortkeys, outerrel->size, outerrel->width))) cost_sort(outersortkeys, outerrel->rows, outerrel->width)))
{ {
/* Use mergeouterpath */ /* Use mergeouterpath */
outersortkeys = NIL; /* no explicit sort step */ outersortkeys = NIL; /* no explicit sort step */
...@@ -516,10 +507,6 @@ match_unsorted_inner(RelOptInfo *joinrel, ...@@ -516,10 +507,6 @@ match_unsorted_inner(RelOptInfo *joinrel,
mergeclauses = get_actual_clauses(mergeclauses); mergeclauses = get_actual_clauses(mergeclauses);
path_list = lappend(path_list, path_list = lappend(path_list,
create_mergejoin_path(joinrel, create_mergejoin_path(joinrel,
outerrel->size,
innerrel->size,
outerrel->width,
innerrel->width,
mergeouterpath, mergeouterpath,
innerpath, innerpath,
merge_pathkeys, merge_pathkeys,
...@@ -563,7 +550,7 @@ hash_inner_and_outer(Query *root, ...@@ -563,7 +550,7 @@ hash_inner_and_outer(Query *root,
Var *leftop = get_leftop(clause); Var *leftop = get_leftop(clause);
Var *rightop = get_rightop(clause); Var *rightop = get_rightop(clause);
Var *innerop; Var *innerop;
Cost innerdisbursion; Selectivity innerdisbursion;
HashPath *hash_path; HashPath *hash_path;
/* find the inner var and estimate its disbursion */ /* find the inner var and estimate its disbursion */
...@@ -574,12 +561,8 @@ hash_inner_and_outer(Query *root, ...@@ -574,12 +561,8 @@ hash_inner_and_outer(Query *root,
innerdisbursion = estimate_disbursion(root, innerop); innerdisbursion = estimate_disbursion(root, innerop);
hash_path = create_hashjoin_path(joinrel, hash_path = create_hashjoin_path(joinrel,
outerrel->size, outerrel->cheapestpath,
innerrel->size, innerrel->cheapestpath,
outerrel->width,
innerrel->width,
(Path *) outerrel->cheapestpath,
(Path *) innerrel->cheapestpath,
lcons(clause, NIL), lcons(clause, NIL),
innerdisbursion); innerdisbursion);
hpath_list = lappend(hpath_list, hash_path); hpath_list = lappend(hpath_list, hash_path);
...@@ -598,7 +581,7 @@ hash_inner_and_outer(Query *root, ...@@ -598,7 +581,7 @@ hash_inner_and_outer(Query *root,
* we know that the inner rel is well-dispersed (or the alternatives * we know that the inner rel is well-dispersed (or the alternatives
* seem much worse). * seem much worse).
*/ */
static Cost static Selectivity
estimate_disbursion(Query *root, Var *var) estimate_disbursion(Query *root, Var *var)
{ {
Oid relid; Oid relid;
...@@ -608,7 +591,7 @@ estimate_disbursion(Query *root, Var *var) ...@@ -608,7 +591,7 @@ estimate_disbursion(Query *root, Var *var)
relid = getrelid(var->varno, root->rtable); relid = getrelid(var->varno, root->rtable);
return (Cost) get_attdisbursion(relid, var->varattno, 0.1); return (Selectivity) get_attdisbursion(relid, var->varattno, 0.1);
} }
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.39 1999/08/16 02:17:51 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.40 2000/01/09 00:26:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -35,8 +35,6 @@ static List *new_join_tlist(List *tlist, int first_resdomno); ...@@ -35,8 +35,6 @@ static List *new_join_tlist(List *tlist, int first_resdomno);
static void build_joinrel_restrict_and_join(RelOptInfo *joinrel, static void build_joinrel_restrict_and_join(RelOptInfo *joinrel,
List *joininfo_list, List *joininfo_list,
Relids join_relids); Relids join_relids);
static void set_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel,
RelOptInfo *inner_rel);
/* /*
* make_rels_by_joins * make_rels_by_joins
...@@ -207,19 +205,15 @@ make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel) ...@@ -207,19 +205,15 @@ make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel)
* The list will be flattened out in update_rels_pathlist_for_joins(). * The list will be flattened out in update_rels_pathlist_for_joins().
*/ */
joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL)); joinrel->relids = lcons(outer_rel->relids, lcons(inner_rel->relids, NIL));
joinrel->indexed = false; joinrel->rows = 0;
joinrel->pages = 0;
joinrel->tuples = 0;
joinrel->size = 0;
joinrel->width = 0; joinrel->width = 0;
/* joinrel->targetlist = NIL;*/ joinrel->targetlist = NIL;
joinrel->pathlist = NIL; joinrel->pathlist = NIL;
joinrel->cheapestpath = (Path *) NULL; joinrel->cheapestpath = (Path *) NULL;
joinrel->pruneable = true; joinrel->pruneable = true;
joinrel->classlist = NULL; joinrel->indexed = false;
joinrel->indexkeys = NULL; joinrel->pages = 0;
joinrel->ordering = NULL; joinrel->tuples = 0;
joinrel->relam = InvalidOid;
joinrel->restrictinfo = NIL; joinrel->restrictinfo = NIL;
joinrel->joininfo = NIL; joinrel->joininfo = NIL;
joinrel->innerjoin = NIL; joinrel->innerjoin = NIL;
...@@ -236,21 +230,22 @@ make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel) ...@@ -236,21 +230,22 @@ make_join_rel(RelOptInfo *outer_rel, RelOptInfo *inner_rel)
/* /*
* Construct restrict and join clause lists for the new joinrel. * Construct restrict and join clause lists for the new joinrel.
*
* nconc(listCopy(x), y) is an idiom for making a new list without
* changing either input list.
*/ */
build_joinrel_restrict_and_join(joinrel, build_joinrel_restrict_and_join(joinrel,
nconc(copyObject(outer_rel->joininfo), nconc(listCopy(outer_rel->joininfo),
copyObject(inner_rel->joininfo)), inner_rel->joininfo),
nconc(listCopy(outer_rel->relids), nconc(listCopy(outer_rel->relids),
listCopy(inner_rel->relids))); inner_rel->relids));
set_joinrel_size(joinrel, outer_rel, inner_rel);
return joinrel; return joinrel;
} }
/* /*
* new_join_tlist * new_join_tlist
* Builds a join relations's target list by keeping those elements that * Builds a join relation's target list by keeping those elements that
* will be in the final target list and any other elements that are still * will be in the final target list and any other elements that are still
* needed for future joins. For a target list entry to still be needed * needed for future joins. For a target list entry to still be needed
* for future joins, its 'joinlist' field must not be empty after removal * for future joins, its 'joinlist' field must not be empty after removal
...@@ -311,18 +306,16 @@ new_join_tlist(List *tlist, ...@@ -311,18 +306,16 @@ new_join_tlist(List *tlist,
* 'joininfo_list' is a list of joininfo nodes from the relations being joined * 'joininfo_list' is a list of joininfo nodes from the relations being joined
* 'join_relids' is a list of all base relids in the new join relation * 'join_relids' is a list of all base relids in the new join relation
* *
* NB: the elements of joininfo_list have all been COPIED and so can safely * NB: Formerly, we made deep(!) copies of each input RestrictInfo to pass
* be destructively modified and/or inserted in the new joinrel's lists. * up to the join relation. I believe this is no longer necessary, because
* The amount of copying going on here is probably vastly excessive, * RestrictInfo nodes are no longer context-dependent. Instead, just add
* since we copied the underlying clauses as well... * the original nodes to the lists belonging to the join relation.
*/ */
static void static void
build_joinrel_restrict_and_join(RelOptInfo *joinrel, build_joinrel_restrict_and_join(RelOptInfo *joinrel,
List *joininfo_list, List *joininfo_list,
Relids join_relids) Relids join_relids)
{ {
List *output_restrictinfo_list = NIL;
List *output_joininfo_list = NIL;
List *xjoininfo; List *xjoininfo;
foreach(xjoininfo, joininfo_list) foreach(xjoininfo, joininfo_list)
...@@ -341,38 +334,25 @@ build_joinrel_restrict_and_join(RelOptInfo *joinrel, ...@@ -341,38 +334,25 @@ build_joinrel_restrict_and_join(RelOptInfo *joinrel,
* Be careful to eliminate duplicates, since we will see the * Be careful to eliminate duplicates, since we will see the
* same clauses arriving from both input relations... * same clauses arriving from both input relations...
*/ */
output_restrictinfo_list = joinrel->restrictinfo =
LispUnion(output_restrictinfo_list, LispUnion(joinrel->restrictinfo,
joininfo->jinfo_restrictinfo); joininfo->jinfo_restrictinfo);
} }
else else
{ {
JoinInfo *old_joininfo;
/* /*
* There might already be a JoinInfo with the same set of * These clauses are still join clauses at this level,
* unjoined relids in output_joininfo_list; don't make a * so find or make the appropriate JoinInfo item for the joinrel,
* redundant entry. * and add the clauses to it (eliminating duplicates).
*/ */
old_joininfo = joininfo_member(new_unjoined_relids, JoinInfo *new_joininfo;
output_joininfo_list);
if (old_joininfo) new_joininfo = find_joininfo_node(joinrel, new_unjoined_relids);
{ new_joininfo->jinfo_restrictinfo =
old_joininfo->jinfo_restrictinfo = LispUnion(new_joininfo->jinfo_restrictinfo,
LispUnion(old_joininfo->jinfo_restrictinfo, joininfo->jinfo_restrictinfo);
joininfo->jinfo_restrictinfo);
}
else
{
joininfo->unjoined_relids = new_unjoined_relids;
output_joininfo_list = lcons(joininfo,
output_joininfo_list);
}
} }
} }
joinrel->restrictinfo = output_restrictinfo_list;
joinrel->joininfo = output_joininfo_list;
} }
/* /*
...@@ -424,36 +404,6 @@ get_cheapest_complete_rel(List *join_rel_list) ...@@ -424,36 +404,6 @@ get_cheapest_complete_rel(List *join_rel_list)
return final_rel; return final_rel;
} }
static void
set_joinrel_size(RelOptInfo *joinrel, RelOptInfo *outer_rel,
RelOptInfo *inner_rel)
{
double dtuples;
int ntuples;
/* avoid overflow ... probably, tuple estimates in RelOptInfo
* just ought to be double ...
*/
dtuples = (double) outer_rel->tuples * (double) inner_rel->tuples;
if (joinrel->restrictinfo != NULL)
dtuples *= product_selec(joinrel->restrictinfo);
if (dtuples >= MAXINT) /* avoid overflow */
ntuples = MAXINT;
else
ntuples = (int) dtuples;
/*
* I bet sizes less than 1 will screw up optimization so make the best
* case 1 instead of 0 - jolly
*/
if (ntuples < 1)
ntuples = 1;
joinrel->tuples = ntuples;
}
/* /*
* Subset-inclusion tests on integer lists. * Subset-inclusion tests on integer lists.
* *
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.32 1999/08/16 02:17:52 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.33 2000/01/09 00:26:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,11 +30,11 @@ static void best_or_subclause_indices(Query *root, RelOptInfo *rel, ...@@ -30,11 +30,11 @@ static void best_or_subclause_indices(Query *root, RelOptInfo *rel,
List *subclauses, List *indices, List *subclauses, List *indices,
List **indexquals, List **indexquals,
List **indexids, List **indexids,
Cost *cost, Cost *selec); Cost *cost);
static void best_or_subclause_index(Query *root, RelOptInfo *rel, static void best_or_subclause_index(Query *root, RelOptInfo *rel,
List *indexqual, List *indices, List *indexqual, List *indices,
int *retIndexid, Oid *retIndexid,
Cost *retCost, Cost *retSelec); Cost *retCost);
/* /*
...@@ -89,7 +89,6 @@ create_or_index_paths(Query *root, ...@@ -89,7 +89,6 @@ create_or_index_paths(Query *root,
List *indexquals; List *indexquals;
List *indexids; List *indexids;
Cost cost; Cost cost;
Cost selec;
best_or_subclause_indices(root, best_or_subclause_indices(root,
rel, rel,
...@@ -97,8 +96,7 @@ create_or_index_paths(Query *root, ...@@ -97,8 +96,7 @@ create_or_index_paths(Query *root,
clausenode->subclauseindices, clausenode->subclauseindices,
&indexquals, &indexquals,
&indexids, &indexids,
&cost, &cost);
&selec);
pathnode->path.pathtype = T_IndexScan; pathnode->path.pathtype = T_IndexScan;
pathnode->path.parent = rel; pathnode->path.parent = rel;
...@@ -114,7 +112,6 @@ create_or_index_paths(Query *root, ...@@ -114,7 +112,6 @@ create_or_index_paths(Query *root,
pathnode->indexqual = indexquals; pathnode->indexqual = indexquals;
pathnode->joinrelids = NIL; /* no join clauses here */ pathnode->joinrelids = NIL; /* no join clauses here */
pathnode->path.path_cost = cost; pathnode->path.path_cost = cost;
clausenode->selectivity = (Cost) selec;
path_list = lappend(path_list, pathnode); path_list = lappend(path_list, pathnode);
} }
...@@ -141,13 +138,12 @@ create_or_index_paths(Query *root, ...@@ -141,13 +138,12 @@ create_or_index_paths(Query *root,
* *
* 'rel' is the node of the relation on which the indexes are defined * 'rel' is the node of the relation on which the indexes are defined
* 'subclauses' are the subclauses of the 'or' clause * 'subclauses' are the subclauses of the 'or' clause
* 'indices' is a list of sublists of the index nodes that matched each * 'indices' is a list of sublists of the IndexOptInfo nodes that matched
* subclause of the 'or' clause * each subclause of the 'or' clause
* '*indexquals' gets the constructed indexquals for the path (a list * '*indexquals' gets the constructed indexquals for the path (a list
* of sublists of clauses, one sublist per scan of the base rel) * of sublists of clauses, one sublist per scan of the base rel)
* '*indexids' gets a list of the index IDs for each scan of the rel * '*indexids' gets a list of the index OIDs for each scan of the rel
* '*cost' gets the total cost of the path * '*cost' gets the total cost of the path
* '*selec' gets the total selectivity of the path.
*/ */
static void static void
best_or_subclause_indices(Query *root, best_or_subclause_indices(Query *root,
...@@ -156,23 +152,20 @@ best_or_subclause_indices(Query *root, ...@@ -156,23 +152,20 @@ best_or_subclause_indices(Query *root,
List *indices, List *indices,
List **indexquals, /* return value */ List **indexquals, /* return value */
List **indexids, /* return value */ List **indexids, /* return value */
Cost *cost, /* return value */ Cost *cost) /* return value */
Cost *selec) /* return value */
{ {
List *slist; List *slist;
*indexquals = NIL; *indexquals = NIL;
*indexids = NIL; *indexids = NIL;
*cost = (Cost) 0.0; *cost = (Cost) 0.0;
*selec = (Cost) 0.0;
foreach(slist, subclauses) foreach(slist, subclauses)
{ {
Expr *subclause = lfirst(slist); Expr *subclause = lfirst(slist);
List *indexqual; List *indexqual;
int best_indexid; Oid best_indexid;
Cost best_cost; Cost best_cost;
Cost best_selec;
/* Convert this 'or' subclause to an indexqual list */ /* Convert this 'or' subclause to an indexqual list */
indexqual = make_ands_implicit(subclause); indexqual = make_ands_implicit(subclause);
...@@ -180,18 +173,13 @@ best_or_subclause_indices(Query *root, ...@@ -180,18 +173,13 @@ best_or_subclause_indices(Query *root,
indexqual = expand_indexqual_conditions(indexqual); indexqual = expand_indexqual_conditions(indexqual);
best_or_subclause_index(root, rel, indexqual, lfirst(indices), best_or_subclause_index(root, rel, indexqual, lfirst(indices),
&best_indexid, &best_cost, &best_selec); &best_indexid, &best_cost);
Assert(best_indexid != InvalidOid);
*indexquals = lappend(*indexquals, indexqual); *indexquals = lappend(*indexquals, indexqual);
*indexids = lappendi(*indexids, best_indexid); *indexids = lappendi(*indexids, best_indexid);
*cost += best_cost; *cost += best_cost;
/* We approximate the selectivity as the sum of the clause
* selectivities (but not more than 1).
* XXX This is too pessimistic, isn't it?
*/
*selec += best_selec;
if (*selec > (Cost) 1.0)
*selec = (Cost) 1.0;
indices = lnext(indices); indices = lnext(indices);
} }
...@@ -205,59 +193,50 @@ best_or_subclause_indices(Query *root, ...@@ -205,59 +193,50 @@ best_or_subclause_indices(Query *root,
* *
* 'rel' is the node of the relation on which the index is defined * 'rel' is the node of the relation on which the index is defined
* 'indexqual' is the indexqual list derived from the subclause * 'indexqual' is the indexqual list derived from the subclause
* 'indices' is a list of index nodes that match the subclause * 'indices' is a list of IndexOptInfo nodes that match the subclause
* '*retIndexid' gets the ID of the best index * '*retIndexid' gets the OID of the best index
* '*retCost' gets the cost of a scan with that index * '*retCost' gets the cost of a scan with that index
* '*retSelec' gets the selectivity of that scan
*/ */
static void static void
best_or_subclause_index(Query *root, best_or_subclause_index(Query *root,
RelOptInfo *rel, RelOptInfo *rel,
List *indexqual, List *indexqual,
List *indices, List *indices,
int *retIndexid, /* return value */ Oid *retIndexid, /* return value */
Cost *retCost, /* return value */ Cost *retCost) /* return value */
Cost *retSelec) /* return value */
{ {
bool first_run = true; bool first_run = true;
List *ilist; List *ilist;
/* if we don't match anything, return zeros */ /* if we don't match anything, return zeros */
*retIndexid = 0; *retIndexid = InvalidOid;
*retCost = (Cost) 0.0; *retCost = 0.0;
*retSelec = (Cost) 0.0;
foreach(ilist, indices) foreach(ilist, indices)
{ {
RelOptInfo *index = (RelOptInfo *) lfirst(ilist); IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
Oid indexid = (Oid) lfirsti(index->relids); long npages;
Selectivity selec;
Cost subcost; Cost subcost;
float npages;
float selec; Assert(IsA(index, IndexOptInfo));
index_selectivity(root, index_selectivity(root,
lfirsti(rel->relids), rel,
indexid, index,
indexqual, indexqual,
&npages, &npages,
&selec); &selec);
subcost = cost_index(indexid, subcost = cost_index(rel, index,
(int) npages, npages, selec,
(Cost) selec,
rel->pages,
rel->tuples,
index->pages,
index->tuples,
false); false);
if (first_run || subcost < *retCost) if (first_run || subcost < *retCost)
{ {
*retIndexid = indexid; *retIndexid = index->indexoid;
*retCost = subcost; *retCost = subcost;
*retSelec = selec;
first_run = false; first_run = false;
} }
} }
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.16 1999/08/22 20:14:42 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.17 2000/01/09 00:26:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -261,7 +261,7 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, ...@@ -261,7 +261,7 @@ get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
* ordering of that key is not interesting. * ordering of that key is not interesting.
*/ */
List * List *
build_index_pathkeys(Query *root, RelOptInfo *rel, RelOptInfo *index) build_index_pathkeys(Query *root, RelOptInfo *rel, IndexOptInfo *index)
{ {
List *retval = NIL; List *retval = NIL;
int *indexkeys = index->indexkeys; int *indexkeys = index->indexkeys;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.43 1999/08/16 02:17:52 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/Attic/prune.c,v 1.44 2000/01/09 00:26:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -90,7 +90,7 @@ merge_rel_with_same_relids(RelOptInfo *rel, List *unmerged_rels) ...@@ -90,7 +90,7 @@ merge_rel_with_same_relids(RelOptInfo *rel, List *unmerged_rels)
* relations), set pointers to the cheapest path and compute rel size. * relations), set pointers to the cheapest path and compute rel size.
*/ */
void void
rels_set_cheapest(List *rel_list) rels_set_cheapest(Query *root, List *rel_list)
{ {
List *x; List *x;
...@@ -101,7 +101,7 @@ rels_set_cheapest(List *rel_list) ...@@ -101,7 +101,7 @@ rels_set_cheapest(List *rel_list)
cheapest = (JoinPath *) set_cheapest(rel, rel->pathlist); cheapest = (JoinPath *) set_cheapest(rel, rel->pathlist);
if (IsA_JoinPath(cheapest)) if (IsA_JoinPath(cheapest))
rel->size = compute_joinrel_size(cheapest); set_joinrel_rows_width(root, rel, cheapest);
else else
elog(ERROR, "rels_set_cheapest: non JoinPath found"); elog(ERROR, "rels_set_cheapest: non JoinPath found");
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.1 1999/11/23 20:06:55 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/tidpath.c,v 1.2 2000/01/09 00:26:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -241,30 +241,27 @@ List *TidqualFromRestrictinfo(List *relids, List * restrictinfo) ...@@ -241,30 +241,27 @@ List *TidqualFromRestrictinfo(List *relids, List * restrictinfo)
List * List *
create_tidscan_joinpaths(RelOptInfo *rel) create_tidscan_joinpaths(RelOptInfo *rel)
{ {
List *rlst = NIL, *lst; List *rlst = NIL,
TidPath *pathnode = (TidPath *)0; *lst;
List *restinfo, *tideval; TidPath *pathnode = (TidPath *) NULL;
List *restinfo,
*tideval;
foreach (lst, rel->joininfo) foreach (lst, rel->joininfo)
{ {
JoinInfo *joininfo = (JoinInfo *)lfirst(lst); JoinInfo *joininfo = (JoinInfo *)lfirst(lst);
restinfo = joininfo->jinfo_restrictinfo; restinfo = joininfo->jinfo_restrictinfo;
tideval = TidqualFromRestrictinfo(rel->relids, restinfo); tideval = TidqualFromRestrictinfo(rel->relids, restinfo);
if (tideval && length(tideval) == 1) if (length(tideval) == 1)
{ {
pathnode = makeNode(TidPath); pathnode = makeNode(TidPath);
pathnode->path.pathtype = T_TidScan; pathnode->path.pathtype = T_TidScan;
pathnode->path.parent = rel; pathnode->path.parent = rel;
pathnode->path.path_cost = 0.0;
pathnode->path.pathkeys = NIL; pathnode->path.pathkeys = NIL;
pathnode->path.path_cost = cost_tidscan(rel, tideval);
pathnode->path.path_cost = cost_tidscan(tideval);
pathnode->tideval = tideval; pathnode->tideval = tideval;
/*
pathnode->tideval = copyObject(tideval);
freeList(tideval);
*/
pathnode->unjoined_relids = joininfo->unjoined_relids; pathnode->unjoined_relids = joininfo->unjoined_relids;
rlst = lappend(rlst, pathnode); rlst = lappend(rlst, pathnode);
} }
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.40 1999/10/07 04:23:06 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.41 2000/01/09 00:26:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,6 +30,7 @@ static void add_restrict_and_join_to_rel(Query *root, Node *clause); ...@@ -30,6 +30,7 @@ static void add_restrict_and_join_to_rel(Query *root, Node *clause);
static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo, static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
Relids join_relids); Relids join_relids);
static void add_vars_to_targetlist(Query *root, List *vars); static void add_vars_to_targetlist(Query *root, List *vars);
static void set_restrictinfo_joininfo(RestrictInfo *restrictinfo);
static void check_mergejoinable(RestrictInfo *restrictinfo); static void check_mergejoinable(RestrictInfo *restrictinfo);
static void check_hashjoinable(RestrictInfo *restrictinfo); static void check_hashjoinable(RestrictInfo *restrictinfo);
...@@ -164,12 +165,6 @@ add_restrict_and_join_to_rel(Query *root, Node *clause) ...@@ -164,12 +165,6 @@ add_restrict_and_join_to_rel(Query *root, Node *clause)
restrictinfo->right_sortop = InvalidOid; restrictinfo->right_sortop = InvalidOid;
restrictinfo->hashjoinoperator = InvalidOid; restrictinfo->hashjoinoperator = InvalidOid;
/*
* The selectivity of the clause must be computed regardless of
* whether it's a restriction or a join clause
*/
restrictinfo->selectivity = compute_clause_selec(root, clause);
/* /*
* Retrieve all relids and vars contained within the clause. * Retrieve all relids and vars contained within the clause.
*/ */
...@@ -189,12 +184,20 @@ add_restrict_and_join_to_rel(Query *root, Node *clause) ...@@ -189,12 +184,20 @@ add_restrict_and_join_to_rel(Query *root, Node *clause)
{ {
/* /*
* 'clause' is a join clause, since there is more than one atom in * 'clause' is a join clause, since there is more than one atom in
* the relid list. Add it to the join lists of all the relevant * the relid list. Set additional RestrictInfo fields for joining.
*/
set_restrictinfo_joininfo(restrictinfo);
/*
* Add clause to the join lists of all the relevant
* relations. (If, perchance, 'clause' contains NO vars, then * relations. (If, perchance, 'clause' contains NO vars, then
* nothing will happen...) * nothing will happen...)
*/ */
add_join_info_to_rels(root, restrictinfo, relids); add_join_info_to_rels(root, restrictinfo, relids);
/* we are going to be doing a join, so add vars to targetlists */ /*
* Add vars used in the join clause to targetlists of member relations,
* so that they will be emitted by the plan nodes that scan those
* relations (else they won't be available at the join node!).
*/
add_vars_to_targetlist(root, vars); add_vars_to_targetlist(root, vars);
} }
} }
...@@ -202,7 +205,7 @@ add_restrict_and_join_to_rel(Query *root, Node *clause) ...@@ -202,7 +205,7 @@ add_restrict_and_join_to_rel(Query *root, Node *clause)
/* /*
* add_join_info_to_rels * add_join_info_to_rels
* For every relation participating in a join clause, add 'restrictinfo' to * For every relation participating in a join clause, add 'restrictinfo' to
* the appropriate joininfo list (creating a new one and adding it to the * the appropriate joininfo list (creating a new list and adding it to the
* appropriate rel node if necessary). * appropriate rel node if necessary).
* *
* 'restrictinfo' describes the join clause * 'restrictinfo' describes the join clause
...@@ -218,8 +221,8 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo, ...@@ -218,8 +221,8 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
foreach(join_relid, join_relids) foreach(join_relid, join_relids)
{ {
int cur_relid = lfirsti(join_relid); int cur_relid = lfirsti(join_relid);
JoinInfo *joininfo;
Relids unjoined_relids = NIL; Relids unjoined_relids = NIL;
JoinInfo *joininfo;
List *otherrel; List *otherrel;
/* Get the relids not equal to the current relid */ /* Get the relids not equal to the current relid */
...@@ -230,18 +233,12 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo, ...@@ -230,18 +233,12 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
} }
/* /*
* Find or make the joininfo node for this combination of rels * Find or make the joininfo node for this combination of rels,
* and add the restrictinfo node to it.
*/ */
joininfo = find_joininfo_node(get_base_rel(root, cur_relid), joininfo = find_joininfo_node(get_base_rel(root, cur_relid),
unjoined_relids); unjoined_relids);
joininfo->jinfo_restrictinfo = lcons(restrictinfo,
/*
* And add the restrictinfo node to it. NOTE that each joininfo
* gets its own copy of the restrictinfo node! (Is this really
* necessary? Possibly ... later parts of the optimizer destructively
* modify restrict/join clauses...)
*/
joininfo->jinfo_restrictinfo = lcons(copyObject((void *) restrictinfo),
joininfo->jinfo_restrictinfo); joininfo->jinfo_restrictinfo);
} }
} }
...@@ -253,36 +250,17 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo, ...@@ -253,36 +250,17 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
*****************************************************************************/ *****************************************************************************/
/* /*
* set_joininfo_mergeable_hashable * set_restrictinfo_joininfo
* Examine each join clause used in a query and set the merge and hash * Examine a RestrictInfo that has been determined to be a join clause,
* info fields in those that are mergejoinable or hashjoinable. * and set the merge and hash info fields if it can be merge/hash joined.
*/ */
void static void
set_joininfo_mergeable_hashable(List *rel_list) set_restrictinfo_joininfo(RestrictInfo *restrictinfo)
{ {
List *x; if (_enable_mergejoin_)
check_mergejoinable(restrictinfo);
foreach(x, rel_list) if (_enable_hashjoin_)
{ check_hashjoinable(restrictinfo);
RelOptInfo *rel = (RelOptInfo *) lfirst(x);
List *y;
foreach(y, rel->joininfo)
{
JoinInfo *joininfo = (JoinInfo *) lfirst(y);
List *z;
foreach(z, joininfo->jinfo_restrictinfo)
{
RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(z);
if (_enable_mergejoin_)
check_mergejoinable(restrictinfo);
if (_enable_hashjoin_)
check_hashjoinable(restrictinfo);
}
}
}
} }
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.48 1999/12/09 05:58:52 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.49 2000/01/09 00:26:36 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -218,8 +218,6 @@ subplanner(Query *root, ...@@ -218,8 +218,6 @@ subplanner(Query *root,
add_restrict_and_join_to_rels(root, qual); add_restrict_and_join_to_rels(root, qual);
add_missing_rels_to_query(root); add_missing_rels_to_query(root);
set_joininfo_mergeable_hashable(root->base_rel_list);
final_rel = make_one_rel(root, root->base_rel_list); final_rel = make_one_rel(root, root->base_rel_list);
if (! final_rel) if (! final_rel)
...@@ -275,7 +273,7 @@ subplanner(Query *root, ...@@ -275,7 +273,7 @@ subplanner(Query *root,
final_rel->cheapestpath->pathkeys)) final_rel->cheapestpath->pathkeys))
{ {
root->query_pathkeys = final_rel->cheapestpath->pathkeys; root->query_pathkeys = final_rel->cheapestpath->pathkeys;
return create_plan(final_rel->cheapestpath); return create_plan(root, final_rel->cheapestpath);
} }
/* /*
...@@ -283,7 +281,7 @@ subplanner(Query *root, ...@@ -283,7 +281,7 @@ subplanner(Query *root,
* cheaper than doing an explicit sort on cheapestpath. * cheaper than doing an explicit sort on cheapestpath.
*/ */
cheapest_cost = final_rel->cheapestpath->path_cost + cheapest_cost = final_rel->cheapestpath->path_cost +
cost_sort(root->query_pathkeys, final_rel->size, final_rel->width); cost_sort(root->query_pathkeys, final_rel->rows, final_rel->width);
sortedpath = get_cheapest_path_for_pathkeys(final_rel->pathlist, sortedpath = get_cheapest_path_for_pathkeys(final_rel->pathlist,
root->query_pathkeys, root->query_pathkeys,
...@@ -294,7 +292,7 @@ subplanner(Query *root, ...@@ -294,7 +292,7 @@ subplanner(Query *root,
{ {
/* Found a better presorted path, use it */ /* Found a better presorted path, use it */
root->query_pathkeys = sortedpath->pathkeys; root->query_pathkeys = sortedpath->pathkeys;
return create_plan(sortedpath); return create_plan(root, sortedpath);
} }
/* otherwise, doing it the hard way is still cheaper */ /* otherwise, doing it the hard way is still cheaper */
} }
...@@ -322,7 +320,7 @@ subplanner(Query *root, ...@@ -322,7 +320,7 @@ subplanner(Query *root,
* backwards scan, we have to convert to Plan format and * backwards scan, we have to convert to Plan format and
* then poke the result. * then poke the result.
*/ */
Plan *sortedplan = create_plan(sortedpath); Plan *sortedplan = create_plan(root, sortedpath);
List *sortedpathkeys; List *sortedpathkeys;
Assert(IsA(sortedplan, IndexScan)); Assert(IsA(sortedplan, IndexScan));
...@@ -350,5 +348,5 @@ subplanner(Query *root, ...@@ -350,5 +348,5 @@ subplanner(Query *root,
* an aggregate function...) * an aggregate function...)
*/ */
root->query_pathkeys = final_rel->cheapestpath->pathkeys; root->query_pathkeys = final_rel->cheapestpath->pathkeys;
return create_plan(final_rel->cheapestpath); return create_plan(root, final_rel->cheapestpath);
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.55 1999/11/23 20:07:00 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.56 2000/01/09 00:26:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
#include "postgres.h" #include "postgres.h"
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "optimizer/pathnode.h" #include "optimizer/pathnode.h"
#include "optimizer/paths.h" #include "optimizer/paths.h"
...@@ -37,10 +35,7 @@ ...@@ -37,10 +35,7 @@
bool bool
path_is_cheaper(Path *path1, Path *path2) path_is_cheaper(Path *path1, Path *path2)
{ {
Cost cost1 = path1->path_cost; return (bool) (path1->path_cost < path2->path_cost);
Cost cost2 = path2->path_cost;
return (bool) (cost1 < cost2);
} }
/* /*
...@@ -60,8 +55,8 @@ set_cheapest(RelOptInfo *parent_rel, List *pathlist) ...@@ -60,8 +55,8 @@ set_cheapest(RelOptInfo *parent_rel, List *pathlist)
List *p; List *p;
Path *cheapest_so_far; Path *cheapest_so_far;
Assert(pathlist != NIL);
Assert(IsA(parent_rel, RelOptInfo)); Assert(IsA(parent_rel, RelOptInfo));
Assert(pathlist != NIL);
cheapest_so_far = (Path *) lfirst(pathlist); cheapest_so_far = (Path *) lfirst(pathlist);
...@@ -192,18 +187,11 @@ Path * ...@@ -192,18 +187,11 @@ Path *
create_seqscan_path(RelOptInfo *rel) create_seqscan_path(RelOptInfo *rel)
{ {
Path *pathnode = makeNode(Path); Path *pathnode = makeNode(Path);
int relid = 0;
pathnode->pathtype = T_SeqScan; pathnode->pathtype = T_SeqScan;
pathnode->parent = rel; pathnode->parent = rel;
pathnode->path_cost = 0.0;
pathnode->pathkeys = NIL; /* seqscan has unordered result */ pathnode->pathkeys = NIL; /* seqscan has unordered result */
pathnode->path_cost = cost_seqscan(rel);
if (rel->relids != NIL) /* can this happen? */
relid = lfirsti(rel->relids);
pathnode->path_cost = cost_seqscan(relid,
rel->pages, rel->tuples);
return pathnode; return pathnode;
} }
...@@ -222,7 +210,7 @@ create_seqscan_path(RelOptInfo *rel) ...@@ -222,7 +210,7 @@ create_seqscan_path(RelOptInfo *rel)
IndexPath * IndexPath *
create_index_path(Query *root, create_index_path(Query *root,
RelOptInfo *rel, RelOptInfo *rel,
RelOptInfo *index, IndexOptInfo *index,
List *restriction_clauses) List *restriction_clauses)
{ {
IndexPath *pathnode = makeNode(IndexPath); IndexPath *pathnode = makeNode(IndexPath);
...@@ -239,8 +227,7 @@ create_index_path(Query *root, ...@@ -239,8 +227,7 @@ create_index_path(Query *root,
* conditions. If we do have restriction conditions to use, they * conditions. If we do have restriction conditions to use, they
* will get inserted below. * will get inserted below.
*/ */
Assert(length(index->relids) == 1); pathnode->indexid = lconsi(index->indexoid, NIL);
pathnode->indexid = index->relids;
pathnode->indexqual = lcons(NIL, NIL); pathnode->indexqual = lcons(NIL, NIL);
pathnode->joinrelids = NIL; /* no join clauses here */ pathnode->joinrelids = NIL; /* no join clauses here */
...@@ -250,13 +237,9 @@ create_index_path(Query *root, ...@@ -250,13 +237,9 @@ create_index_path(Query *root,
* We have no restriction clauses, so compute scan cost using * We have no restriction clauses, so compute scan cost using
* selectivity of 1.0. * selectivity of 1.0.
*/ */
pathnode->path.path_cost = cost_index(lfirsti(index->relids), pathnode->path.path_cost = cost_index(rel, index,
index->pages, index->pages,
1.0, (Selectivity) 1.0,
rel->pages,
rel->tuples,
index->pages,
index->tuples,
false); false);
} }
else else
...@@ -266,9 +249,8 @@ create_index_path(Query *root, ...@@ -266,9 +249,8 @@ create_index_path(Query *root,
* restriction clause(s). Also, place indexqual in path node. * restriction clause(s). Also, place indexqual in path node.
*/ */
List *indexquals; List *indexquals;
float npages; long npages;
float selec; Selectivity selec;
Cost clausesel;
indexquals = get_actual_clauses(restriction_clauses); indexquals = get_actual_clauses(restriction_clauses);
/* expand special operators to indexquals the executor can handle */ /* expand special operators to indexquals the executor can handle */
...@@ -280,39 +262,15 @@ create_index_path(Query *root, ...@@ -280,39 +262,15 @@ create_index_path(Query *root,
lfirst(pathnode->indexqual) = indexquals; lfirst(pathnode->indexqual) = indexquals;
index_selectivity(root, index_selectivity(root,
lfirsti(rel->relids), rel,
lfirsti(index->relids), index,
indexquals, indexquals,
&npages, &npages,
&selec); &selec);
pathnode->path.path_cost = cost_index(lfirsti(index->relids), pathnode->path.path_cost = cost_index(rel, index,
(int) npages, npages, selec,
selec,
rel->pages,
rel->tuples,
index->pages,
index->tuples,
false); false);
/*
* Set selectivities of clauses used with index to the selectivity
* of this index, subdividing the selectivity equally over each of
* the clauses. To the extent that index_selectivity() can make a
* better estimate of the joint selectivity of these clauses than
* the product of individual estimates from compute_clause_selec()
* would be, this should give us a more accurate estimate of the
* total selectivity of all the clauses.
*
* XXX If there is more than one useful index for this rel, and the
* indexes can be used with different but overlapping groups of
* restriction clauses, we may end up with too optimistic an estimate,
* since set_clause_selectivities() will save the minimum of the
* per-clause selectivity estimated with each index. But that should
* be fairly unlikely for typical index usage.
*/
clausesel = pow(selec, 1.0 / (double) length(restriction_clauses));
set_clause_selectivities(restriction_clauses, clausesel);
} }
return pathnode; return pathnode;
...@@ -331,14 +289,12 @@ create_tidscan_path(RelOptInfo *rel, List *tideval) ...@@ -331,14 +289,12 @@ create_tidscan_path(RelOptInfo *rel, List *tideval)
pathnode->path.pathtype = T_TidScan; pathnode->path.pathtype = T_TidScan;
pathnode->path.parent = rel; pathnode->path.parent = rel;
pathnode->path.path_cost = 0.0;
pathnode->path.pathkeys = NIL; pathnode->path.pathkeys = NIL;
pathnode->path.path_cost = cost_tidscan(rel, tideval);
pathnode->path.path_cost = cost_tidscan(tideval);
/* divide selectivity for each clause to get an equal selectivity /* divide selectivity for each clause to get an equal selectivity
* as IndexScan does OK ? * as IndexScan does OK ?
*/ */
pathnode->tideval = copyObject(tideval); pathnode->tideval = copyObject(tideval); /* is copy really necessary? */
pathnode->unjoined_relids = NIL; pathnode->unjoined_relids = NIL;
return pathnode; return pathnode;
...@@ -350,7 +306,6 @@ create_tidscan_path(RelOptInfo *rel, List *tideval) ...@@ -350,7 +306,6 @@ create_tidscan_path(RelOptInfo *rel, List *tideval)
* relations. * relations.
* *
* 'joinrel' is the join relation. * 'joinrel' is the join relation.
* 'outer_rel' is the outer join relation
* 'outer_path' is the outer path * 'outer_path' is the outer path
* 'inner_path' is the inner path * 'inner_path' is the inner path
* 'pathkeys' are the path keys of the new join path * 'pathkeys' are the path keys of the new join path
...@@ -360,7 +315,6 @@ create_tidscan_path(RelOptInfo *rel, List *tideval) ...@@ -360,7 +315,6 @@ create_tidscan_path(RelOptInfo *rel, List *tideval)
*/ */
NestPath * NestPath *
create_nestloop_path(RelOptInfo *joinrel, create_nestloop_path(RelOptInfo *joinrel,
RelOptInfo *outer_rel,
Path *outer_path, Path *outer_path,
Path *inner_path, Path *inner_path,
List *pathkeys) List *pathkeys)
...@@ -371,15 +325,10 @@ create_nestloop_path(RelOptInfo *joinrel, ...@@ -371,15 +325,10 @@ create_nestloop_path(RelOptInfo *joinrel,
pathnode->path.parent = joinrel; pathnode->path.parent = joinrel;
pathnode->outerjoinpath = outer_path; pathnode->outerjoinpath = outer_path;
pathnode->innerjoinpath = inner_path; pathnode->innerjoinpath = inner_path;
pathnode->pathinfo = joinrel->restrictinfo;
pathnode->path.pathkeys = pathkeys; pathnode->path.pathkeys = pathkeys;
pathnode->path.path_cost = cost_nestloop(outer_path->path_cost, pathnode->path.path_cost = cost_nestloop(outer_path,
inner_path->path_cost, inner_path,
outer_rel->size,
inner_path->parent->size,
page_size(outer_rel->size,
outer_rel->width),
IsA(inner_path, IndexPath)); IsA(inner_path, IndexPath));
return pathnode; return pathnode;
...@@ -391,10 +340,6 @@ create_nestloop_path(RelOptInfo *joinrel, ...@@ -391,10 +340,6 @@ create_nestloop_path(RelOptInfo *joinrel,
* two relations * two relations
* *
* 'joinrel' is the join relation * 'joinrel' is the join relation
* 'outersize' is the number of tuples in the outer relation
* 'innersize' is the number of tuples in the inner relation
* 'outerwidth' is the number of bytes per tuple in the outer relation
* 'innerwidth' is the number of bytes per tuple in the inner relation
* 'outer_path' is the outer path * 'outer_path' is the outer path
* 'inner_path' is the inner path * 'inner_path' is the inner path
* 'pathkeys' are the path keys of the new join path * 'pathkeys' are the path keys of the new join path
...@@ -405,10 +350,6 @@ create_nestloop_path(RelOptInfo *joinrel, ...@@ -405,10 +350,6 @@ create_nestloop_path(RelOptInfo *joinrel,
*/ */
MergePath * MergePath *
create_mergejoin_path(RelOptInfo *joinrel, create_mergejoin_path(RelOptInfo *joinrel,
int outersize,
int innersize,
int outerwidth,
int innerwidth,
Path *outer_path, Path *outer_path,
Path *inner_path, Path *inner_path,
List *pathkeys, List *pathkeys,
...@@ -433,19 +374,14 @@ create_mergejoin_path(RelOptInfo *joinrel, ...@@ -433,19 +374,14 @@ create_mergejoin_path(RelOptInfo *joinrel,
pathnode->jpath.path.parent = joinrel; pathnode->jpath.path.parent = joinrel;
pathnode->jpath.outerjoinpath = outer_path; pathnode->jpath.outerjoinpath = outer_path;
pathnode->jpath.innerjoinpath = inner_path; pathnode->jpath.innerjoinpath = inner_path;
pathnode->jpath.pathinfo = joinrel->restrictinfo;
pathnode->jpath.path.pathkeys = pathkeys; pathnode->jpath.path.pathkeys = pathkeys;
pathnode->path_mergeclauses = mergeclauses; pathnode->path_mergeclauses = mergeclauses;
pathnode->outersortkeys = outersortkeys; pathnode->outersortkeys = outersortkeys;
pathnode->innersortkeys = innersortkeys; pathnode->innersortkeys = innersortkeys;
pathnode->jpath.path.path_cost = cost_mergejoin(outer_path->path_cost, pathnode->jpath.path.path_cost = cost_mergejoin(outer_path,
inner_path->path_cost, inner_path,
outersortkeys, outersortkeys,
innersortkeys, innersortkeys);
outersize,
innersize,
outerwidth,
innerwidth);
return pathnode; return pathnode;
} }
...@@ -455,10 +391,6 @@ create_mergejoin_path(RelOptInfo *joinrel, ...@@ -455,10 +391,6 @@ create_mergejoin_path(RelOptInfo *joinrel,
* Creates a pathnode corresponding to a hash join between two relations. * Creates a pathnode corresponding to a hash join between two relations.
* *
* 'joinrel' is the join relation * 'joinrel' is the join relation
* 'outersize' is the number of tuples in the outer relation
* 'innersize' is the number of tuples in the inner relation
* 'outerwidth' is the number of bytes per tuple in the outer relation
* 'innerwidth' is the number of bytes per tuple in the inner relation
* 'outer_path' is the cheapest outer path * 'outer_path' is the cheapest outer path
* 'inner_path' is the cheapest inner path * 'inner_path' is the cheapest inner path
* 'hashclauses' is a list of the hash join clause (always a 1-element list) * 'hashclauses' is a list of the hash join clause (always a 1-element list)
...@@ -467,14 +399,10 @@ create_mergejoin_path(RelOptInfo *joinrel, ...@@ -467,14 +399,10 @@ create_mergejoin_path(RelOptInfo *joinrel,
*/ */
HashPath * HashPath *
create_hashjoin_path(RelOptInfo *joinrel, create_hashjoin_path(RelOptInfo *joinrel,
int outersize,
int innersize,
int outerwidth,
int innerwidth,
Path *outer_path, Path *outer_path,
Path *inner_path, Path *inner_path,
List *hashclauses, List *hashclauses,
Cost innerdisbursion) Selectivity innerdisbursion)
{ {
HashPath *pathnode = makeNode(HashPath); HashPath *pathnode = makeNode(HashPath);
...@@ -482,14 +410,11 @@ create_hashjoin_path(RelOptInfo *joinrel, ...@@ -482,14 +410,11 @@ create_hashjoin_path(RelOptInfo *joinrel,
pathnode->jpath.path.parent = joinrel; pathnode->jpath.path.parent = joinrel;
pathnode->jpath.outerjoinpath = outer_path; pathnode->jpath.outerjoinpath = outer_path;
pathnode->jpath.innerjoinpath = inner_path; pathnode->jpath.innerjoinpath = inner_path;
pathnode->jpath.pathinfo = joinrel->restrictinfo;
/* A hashjoin never has pathkeys, since its ordering is unpredictable */ /* A hashjoin never has pathkeys, since its ordering is unpredictable */
pathnode->jpath.path.pathkeys = NIL; pathnode->jpath.path.pathkeys = NIL;
pathnode->path_hashclauses = hashclauses; pathnode->path_hashclauses = hashclauses;
pathnode->jpath.path.path_cost = cost_hashjoin(outer_path->path_cost, pathnode->jpath.path.path_cost = cost_hashjoin(outer_path,
inner_path->path_cost, inner_path,
outersize, innersize,
outerwidth, innerwidth,
innerdisbursion); innerdisbursion);
return pathnode; return pathnode;
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.19 1999/08/16 02:17:58 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.20 2000/01/09 00:26:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,21 +37,15 @@ get_base_rel(Query *root, int relid) ...@@ -37,21 +37,15 @@ get_base_rel(Query *root, int relid)
{ {
rel = makeNode(RelOptInfo); rel = makeNode(RelOptInfo);
rel->relids = relids; rel->relids = relids;
rel->indexed = false; rel->rows = 0;
rel->pages = 0;
rel->tuples = 0;
rel->size = 0;
rel->width = 0; rel->width = 0;
rel->targetlist = NIL; rel->targetlist = NIL;
rel->pathlist = NIL; rel->pathlist = NIL;
rel->cheapestpath = (Path *) NULL; rel->cheapestpath = (Path *) NULL;
rel->pruneable = true; rel->pruneable = true;
rel->classlist = NULL; rel->indexed = false;
rel->indexkeys = NULL; rel->pages = 0;
rel->ordering = NULL; rel->tuples = 0;
rel->relam = InvalidOid;
rel->indproc = InvalidOid;
rel->indpred = NIL;
rel->restrictinfo = NIL; rel->restrictinfo = NIL;
rel->joininfo = NIL; rel->joininfo = NIL;
rel->innerjoin = NIL; rel->innerjoin = NIL;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.44 1999/11/25 00:21:34 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.45 2000/01/09 00:26:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -36,6 +36,9 @@ ...@@ -36,6 +36,9 @@
/* are we looking at a functional index selectivity request? */ /* are we looking at a functional index selectivity request? */
#define FunctionalSelectivity(nIndKeys,attNum) ((attNum)==InvalidAttrNumber) #define FunctionalSelectivity(nIndKeys,attNum) ((attNum)==InvalidAttrNumber)
/* default selectivity estimate for equalities such as "A = b" */
#define DEFAULT_EQ_SEL 0.01
/* default selectivity estimate for inequalities such as "A < b" */ /* default selectivity estimate for inequalities such as "A < b" */
#define DEFAULT_INEQ_SEL (1.0 / 3.0) #define DEFAULT_INEQ_SEL (1.0 / 3.0)
...@@ -75,7 +78,7 @@ eqsel(Oid opid, ...@@ -75,7 +78,7 @@ eqsel(Oid opid,
result = (float64) palloc(sizeof(float64data)); result = (float64) palloc(sizeof(float64data));
if (NONVALUE(attno) || NONVALUE(relid)) if (NONVALUE(attno) || NONVALUE(relid))
*result = 0.1; *result = DEFAULT_EQ_SEL;
else else
{ {
Oid typid; Oid typid;
...@@ -369,15 +372,16 @@ eqjoinsel(Oid opid, ...@@ -369,15 +372,16 @@ eqjoinsel(Oid opid,
float64data num1, float64data num1,
num2, num2,
min; min;
bool unknown1 = NONVALUE(relid1) || NONVALUE(attno1);
bool unknown2 = NONVALUE(relid2) || NONVALUE(attno2);
result = (float64) palloc(sizeof(float64data)); result = (float64) palloc(sizeof(float64data));
if (NONVALUE(attno1) || NONVALUE(relid1) || if (unknown1 && unknown2)
NONVALUE(attno2) || NONVALUE(relid2)) *result = DEFAULT_EQ_SEL;
*result = 0.1;
else else
{ {
num1 = get_attdisbursion(relid1, attno1, 0.01); num1 = unknown1 ? 1.0 : get_attdisbursion(relid1, attno1, 0.01);
num2 = get_attdisbursion(relid2, attno2, 0.01); num2 = unknown2 ? 1.0 : get_attdisbursion(relid2, attno2, 0.01);
/* /*
* The join selectivity cannot be more than num2, since each * The join selectivity cannot be more than num2, since each
* tuple in table 1 could match no more than num2 fraction of * tuple in table 1 could match no more than num2 fraction of
...@@ -386,6 +390,9 @@ eqjoinsel(Oid opid, ...@@ -386,6 +390,9 @@ eqjoinsel(Oid opid,
* less). By the same reasoning it is not more than num1. * less). By the same reasoning it is not more than num1.
* The min is therefore an upper bound. * The min is therefore an upper bound.
* *
* If we know the disbursion of only one side, use it; the reasoning
* above still works.
*
* XXX can we make a better estimate here? Using the nullfrac * XXX can we make a better estimate here? Using the nullfrac
* statistic might be helpful, for example. Assuming the operator * statistic might be helpful, for example. Assuming the operator
* is strict (does not succeed for null inputs) then the selectivity * is strict (does not succeed for null inputs) then the selectivity
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: nodes.h,v 1.59 1999/12/16 17:24:19 momjian Exp $ * $Id: nodes.h,v 1.60 2000/01/09 00:26:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -82,6 +82,7 @@ typedef enum NodeTag ...@@ -82,6 +82,7 @@ typedef enum NodeTag
T_JoinInfo, T_JoinInfo,
T_Stream, T_Stream,
T_TidPath, T_TidPath,
T_IndexOptInfo,
/*--------------------- /*---------------------
* TAGS FOR EXECUTOR NODES (execnodes.h) * TAGS FOR EXECUTOR NODES (execnodes.h)
...@@ -286,12 +287,17 @@ extern void *copyObject(void *obj); ...@@ -286,12 +287,17 @@ extern void *copyObject(void *obj);
extern bool equal(void *a, void *b); extern bool equal(void *a, void *b);
/* ---------------- /*
* I don't know why this is here. Most likely a hack.. * Typedefs for identifying qualifier selectivities and plan costs as such.
* -cim 6/3/90 * These are just plain "double"s, but declaring a variable as Selectivity
* ---------------- * or Cost makes the intent more obvious.
*
* These could have gone into plannodes.h or some such, but many files
* depend on them...
*/ */
typedef float Cost; typedef double Selectivity; /* fraction of tuples a qualifier will pass */
typedef double Cost; /* execution cost (in page-access units) */
/* /*
* CmdType - * CmdType -
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: plannodes.h,v 1.34 1999/11/23 20:07:02 momjian Exp $ * $Id: plannodes.h,v 1.35 2000/01/09 00:26:43 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -63,10 +63,12 @@ ...@@ -63,10 +63,12 @@
typedef struct Plan typedef struct Plan
{ {
NodeTag type; NodeTag type;
/* planner's estimates of cost and result size */
Cost cost; Cost cost;
int plan_size; double plan_rows;
int plan_width; int plan_width;
int plan_tupperpage;
EState *state; /* at execution time, state's of EState *state; /* at execution time, state's of
* individual nodes point to one EState * individual nodes point to one EState
* for the whole top-level plan */ * for the whole top-level plan */
...@@ -185,10 +187,10 @@ typedef struct IndexScan ...@@ -185,10 +187,10 @@ typedef struct IndexScan
*/ */
typedef struct TidScan typedef struct TidScan
{ {
Scan scan; Scan scan;
bool needRescan; bool needRescan;
List *tideval; List *tideval;
TidScanState *tidstate; TidScanState *tidstate;
} TidScan; } TidScan;
/* /*
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: relation.h,v 1.39 1999/11/23 20:07:02 momjian Exp $ * $Id: relation.h,v 1.40 2000/01/09 00:26:44 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -33,13 +33,10 @@ typedef List *Relids; ...@@ -33,13 +33,10 @@ typedef List *Relids;
* *
* relids - List of base-relation identifiers; it is a base relation * relids - List of base-relation identifiers; it is a base relation
* if there is just one, a join relation if more than one * if there is just one, a join relation if more than one
* indexed - true if the relation has secondary indices * rows - estimated number of tuples in the relation after restriction
* pages - number of pages in the relation * clauses have been applied (ie, output rows of a plan for it)
* tuples - number of tuples in the relation
* size - estimated number of tuples in the relation after restriction
* clauses have been applied
* width - avg. number of bytes per tuple in the relation after the * width - avg. number of bytes per tuple in the relation after the
* appropriate projections have been done * appropriate projections have been done (ie, output width)
* targetlist - List of TargetList nodes * targetlist - List of TargetList nodes
* pathlist - List of Path nodes, one for each potentially useful * pathlist - List of Path nodes, one for each potentially useful
* method of generating the relation * method of generating the relation
...@@ -47,20 +44,11 @@ typedef List *Relids; ...@@ -47,20 +44,11 @@ typedef List *Relids;
* pruneable - flag to let the planner know whether it can prune the * pruneable - flag to let the planner know whether it can prune the
* pathlist of this RelOptInfo or not. * pathlist of this RelOptInfo or not.
* *
* * If the relation is a (secondary) index it will have the following * * If the relation is a base relation it will have these fields set:
* fields set:
*
* classlist - List of PG_AMOPCLASS OIDs for the index
* indexkeys - List of base-relation attribute numbers that are index keys
* ordering - List of PG_OPERATOR OIDs which order the indexscan result
* relam - the OID of the pg_am of the index
*
* NB. the last element of the arrays classlist, indexkeys and ordering
* is always 0.
* *
* Index relations do not participate in the join tree in the way * indexed - true if the relation has secondary indices
* that regular base relations do, but it is still convenient to * pages - number of disk pages in relation
* represent them by RelOptInfos. * tuples - number of tuples in relation (not considering restrictions)
* *
* * The presence of the remaining fields depends on the restrictions * * The presence of the remaining fields depends on the restrictions
* and joins that the relation participates in: * and joins that the relation participates in:
...@@ -79,16 +67,11 @@ typedef struct RelOptInfo ...@@ -79,16 +67,11 @@ typedef struct RelOptInfo
NodeTag type; NodeTag type;
/* all relations included in this RelOptInfo */ /* all relations included in this RelOptInfo */
Relids relids; /* integer list of base relids */ Relids relids; /* integer list of base relids (RT indexes) */
/* catalog statistics information */
bool indexed;
int pages;
int tuples;
/* estimates generated by planner. XXX int is probably too small... */ /* size estimates generated by planner */
int size; double rows; /* estimated number of result tuples */
int width; int width; /* estimated avg width of result tuples */
/* materialization information */ /* materialization information */
List *targetlist; List *targetlist;
...@@ -96,14 +79,10 @@ typedef struct RelOptInfo ...@@ -96,14 +79,10 @@ typedef struct RelOptInfo
struct Path *cheapestpath; struct Path *cheapestpath;
bool pruneable; bool pruneable;
/* used solely by indices: */ /* statistics from pg_class (only valid if it's a base rel!) */
Oid *classlist; /* classes of AM operators */ bool indexed;
int *indexkeys; /* keys over which we're indexing */ long pages;
Oid *ordering; /* OIDs of sort operators for each key */ double tuples;
Oid relam; /* OID of the access method (in pg_am) */
Oid indproc; /* if a functional index */
List *indpred; /* if a partial index */
/* used by various scans and joins: */ /* used by various scans and joins: */
List *restrictinfo; /* RestrictInfo structures */ List *restrictinfo; /* RestrictInfo structures */
...@@ -115,6 +94,48 @@ typedef struct RelOptInfo ...@@ -115,6 +94,48 @@ typedef struct RelOptInfo
*/ */
} RelOptInfo; } RelOptInfo;
/*
* IndexOptInfo
* Per-index information for planning/optimization
*
* Prior to Postgres 7.0, RelOptInfo was used to describe both relations
* and indexes, but that created confusion without actually doing anything
* useful. So now we have a separate IndexOptInfo struct for indexes.
*
* indexoid - OID of the index relation itself
* pages - number of disk pages in index
* tuples - number of index tuples in index
* classlist - List of PG_AMOPCLASS OIDs for the index
* indexkeys - List of base-relation attribute numbers that are index keys
* ordering - List of PG_OPERATOR OIDs which order the indexscan result
* relam - the OID of the pg_am of the index
* indproc - OID of the function if a functional index, else 0
* indpred - index predicate if a partial index, else NULL
*
* NB. the last element of the arrays classlist, indexkeys and ordering
* is always 0.
*/
typedef struct IndexOptInfo
{
NodeTag type;
Oid indexoid; /* OID of the index relation */
/* statistics from pg_class */
long pages;
double tuples;
/* index descriptor information */
Oid *classlist; /* classes of AM operators */
int *indexkeys; /* keys over which we're indexing */
Oid *ordering; /* OIDs of sort operators for each key */
Oid relam; /* OID of the access method (in pg_am) */
Oid indproc; /* if a functional index */
List *indpred; /* if a partial index */
} IndexOptInfo;
/* /*
* PathKeys * PathKeys
* *
...@@ -208,8 +229,6 @@ typedef struct JoinPath ...@@ -208,8 +229,6 @@ typedef struct JoinPath
{ {
Path path; Path path;
List *pathinfo; /* copy of parent->restrictinfo; REMOVE? */
Path *outerjoinpath; /* path for the outer side of the join */ Path *outerjoinpath; /* path for the outer side of the join */
Path *innerjoinpath; /* path for the inner side of the join */ Path *innerjoinpath; /* path for the inner side of the join */
} JoinPath; } JoinPath;
...@@ -296,10 +315,10 @@ typedef struct RestrictInfo ...@@ -296,10 +315,10 @@ typedef struct RestrictInfo
NodeTag type; NodeTag type;
Expr *clause; /* the represented clause of WHERE cond */ Expr *clause; /* the represented clause of WHERE cond */
Cost selectivity; /* estimated selectivity */
/* only used if clause is an OR clause: */ /* only used if clause is an OR clause: */
List *subclauseindices; /* lists of indexes matching subclauses */ List *subclauseindices; /* indexes matching subclauses */
/* subclauseindices is a List of Lists of IndexOptInfos */
/* valid if clause is mergejoinable, else InvalidOid: */ /* valid if clause is mergejoinable, else InvalidOid: */
Oid mergejoinoperator; /* copy of clause operator */ Oid mergejoinoperator; /* copy of clause operator */
...@@ -346,7 +365,8 @@ typedef struct JoinInfo ...@@ -346,7 +365,8 @@ typedef struct JoinInfo
* cinfo -- if NULL, this stream node referes to the path node. * cinfo -- if NULL, this stream node referes to the path node.
* Otherwise this is a pointer to the current clause. * Otherwise this is a pointer to the current clause.
* clausetype -- whether cinfo is in loc_restrictinfo or pathinfo in the * clausetype -- whether cinfo is in loc_restrictinfo or pathinfo in the
* path node (XXX this is now used only by dead code...) * path node (XXX this is now used only by dead code, which is
* good because the distinction no longer exists...)
* upstream -- linked list pointer upwards * upstream -- linked list pointer upwards
* downstream -- ditto, downwards * downstream -- ditto, downwards
* groupup -- whether or not this node is in a group with the node upstream * groupup -- whether or not this node is in a group with the node upstream
...@@ -365,7 +385,7 @@ typedef struct Stream ...@@ -365,7 +385,7 @@ typedef struct Stream
StreamPtr downstream; StreamPtr downstream;
bool groupup; bool groupup;
Cost groupcost; Cost groupcost;
Cost groupsel; Selectivity groupsel;
} Stream; } Stream;
#endif /* RELATION_H */ #endif /* RELATION_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: cost.h,v 1.24 1999/11/23 20:07:05 momjian Exp $ * $Id: cost.h,v 1.25 2000/01/09 00:26:46 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -33,34 +33,28 @@ extern bool _enable_mergejoin_; ...@@ -33,34 +33,28 @@ extern bool _enable_mergejoin_;
extern bool _enable_hashjoin_; extern bool _enable_hashjoin_;
extern bool _enable_tidscan_; extern bool _enable_tidscan_;
extern Cost cost_seqscan(int relid, int relpages, int reltuples); extern Cost cost_seqscan(RelOptInfo *baserel);
extern Cost cost_index(Oid indexid, int expected_indexpages, Cost selec, extern Cost cost_index(RelOptInfo *baserel, IndexOptInfo *index,
int relpages, int reltuples, int indexpages, long expected_indexpages, Selectivity selec,
int indextuples, bool is_injoin); bool is_injoin);
extern Cost cost_tidscan(List *evallist); extern Cost cost_tidscan(RelOptInfo *baserel, List *tideval);
extern Cost cost_sort(List *pathkeys, int tuples, int width); extern Cost cost_sort(List *pathkeys, double tuples, int width);
extern Cost cost_nestloop(Cost outercost, Cost innercost, int outertuples, extern Cost cost_nestloop(Path *outer_path, Path *inner_path,
int innertuples, int outerpages, bool is_indexjoin); bool is_indexjoin);
extern Cost cost_mergejoin(Cost outercost, Cost innercost, extern Cost cost_mergejoin(Path *outer_path, Path *inner_path,
List *outersortkeys, List *innersortkeys, List *outersortkeys, List *innersortkeys);
int outersize, int innersize, int outerwidth, int innerwidth); extern Cost cost_hashjoin(Path *outer_path, Path *inner_path,
extern Cost cost_hashjoin(Cost outercost, Cost innercost, Selectivity innerdisbursion);
int outersize, int innersize, extern void set_rel_rows_width(Query *root, RelOptInfo *rel);
int outerwidth, int innerwidth, extern void set_joinrel_rows_width(Query *root, RelOptInfo *rel,
Cost innerdisbursion); JoinPath *joinpath);
extern int compute_rel_size(RelOptInfo *rel);
extern int compute_rel_width(RelOptInfo *rel);
extern int compute_joinrel_size(JoinPath *joinpath);
extern int page_size(int tuples, int width);
/* /*
* prototypes for fuctions in clausesel.h * prototypes for clausesel.c
* routines to compute clause selectivities * routines to compute clause selectivities
*/ */
extern void set_clause_selectivities(List *restrictinfo_list, Cost new_selectivity); extern Selectivity restrictlist_selec(Query *root, List *restrictinfo_list);
extern Cost product_selec(List *restrictinfo_list); extern Selectivity clauselist_selec(Query *root, List *clauses);
extern void set_rest_relselec(Query *root, List *rel_list); extern Selectivity compute_clause_selec(Query *root, Node *clause);
extern void set_rest_selec(Query *root, List *restrictinfo_list);
extern Cost compute_clause_selec(Query *root, Node *clause);
#endif /* COST_H */ #endif /* COST_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: pathnode.h,v 1.22 1999/11/23 20:07:06 momjian Exp $ * $Id: pathnode.h,v 1.23 2000/01/09 00:26:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -21,26 +21,27 @@ ...@@ -21,26 +21,27 @@
extern bool path_is_cheaper(Path *path1, Path *path2); extern bool path_is_cheaper(Path *path1, Path *path2);
extern Path *set_cheapest(RelOptInfo *parent_rel, List *pathlist); extern Path *set_cheapest(RelOptInfo *parent_rel, List *pathlist);
extern List *add_pathlist(RelOptInfo *parent_rel, List *old_paths, extern List *add_pathlist(RelOptInfo *parent_rel, List *old_paths,
List *new_paths); List *new_paths);
extern Path *create_seqscan_path(RelOptInfo *rel); extern Path *create_seqscan_path(RelOptInfo *rel);
extern IndexPath *create_index_path(Query *root, RelOptInfo *rel, extern IndexPath *create_index_path(Query *root, RelOptInfo *rel,
RelOptInfo *index, List *restriction_clauses); IndexOptInfo *index,
List *restriction_clauses);
extern TidPath *create_tidscan_path(RelOptInfo *rel, List *tideval); extern TidPath *create_tidscan_path(RelOptInfo *rel, List *tideval);
extern NestPath *create_nestloop_path(RelOptInfo *joinrel, extern NestPath *create_nestloop_path(RelOptInfo *joinrel,
RelOptInfo *outer_rel, Path *outer_path, Path *inner_path, Path *outer_path, Path *inner_path,
List *pathkeys); List *pathkeys);
extern MergePath *create_mergejoin_path(RelOptInfo *joinrel, int outersize, extern MergePath *create_mergejoin_path(RelOptInfo *joinrel, Path *outer_path,
int innersize, int outerwidth, int innerwidth, Path *outer_path, Path *inner_path, List *pathkeys,
Path *inner_path, List *pathkeys, List *mergeclauses,
List *mergeclauses, List *outersortkeys, List *innersortkeys); List *outersortkeys,
List *innersortkeys);
extern HashPath *create_hashjoin_path(RelOptInfo *joinrel, int outersize,
int innersize, int outerwidth, int innerwidth, Path *outer_path, extern HashPath *create_hashjoin_path(RelOptInfo *joinrel, Path *outer_path,
Path *inner_path, List *hashclauses, Cost innerdisbursion); Path *inner_path, List *hashclauses,
Selectivity innerdisbursion);
/* /*
* prototypes for rel.c * prototypes for rel.c
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: paths.h,v 1.36 1999/11/23 20:07:06 momjian Exp $ * $Id: paths.h,v 1.37 2000/01/09 00:26:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -28,6 +28,8 @@ extern RelOptInfo *make_one_rel(Query *root, List *rels); ...@@ -28,6 +28,8 @@ extern RelOptInfo *make_one_rel(Query *root, List *rels);
extern List *create_index_paths(Query *root, RelOptInfo *rel, List *indices, extern List *create_index_paths(Query *root, RelOptInfo *rel, List *indices,
List *restrictinfo_list, List *restrictinfo_list,
List *joininfo_list); List *joininfo_list);
extern Oid indexable_operator(Expr *clause, Oid opclass, Oid relam,
bool indexkey_on_left);
extern List *expand_indexqual_conditions(List *indexquals); extern List *expand_indexqual_conditions(List *indexquals);
/* /*
...@@ -65,7 +67,7 @@ extern bool pathkeys_contained_in(List *keys1, List *keys2); ...@@ -65,7 +67,7 @@ extern bool pathkeys_contained_in(List *keys1, List *keys2);
extern Path *get_cheapest_path_for_pathkeys(List *paths, List *pathkeys, extern Path *get_cheapest_path_for_pathkeys(List *paths, List *pathkeys,
bool indexpaths_only); bool indexpaths_only);
extern List *build_index_pathkeys(Query *root, RelOptInfo *rel, extern List *build_index_pathkeys(Query *root, RelOptInfo *rel,
RelOptInfo *index); IndexOptInfo *index);
extern List *build_join_pathkeys(List *outer_pathkeys, extern List *build_join_pathkeys(List *outer_pathkeys,
List *join_rel_tlist, List *joinclauses); List *join_rel_tlist, List *joinclauses);
extern bool commute_pathkeys(List *pathkeys); extern bool commute_pathkeys(List *pathkeys);
...@@ -93,7 +95,7 @@ extern bool is_subset(List *s1, List *s2); ...@@ -93,7 +95,7 @@ extern bool is_subset(List *s1, List *s2);
* prototypes for path/prune.c * prototypes for path/prune.c
*/ */
extern void merge_rels_with_same_relids(List *rel_list); extern void merge_rels_with_same_relids(List *rel_list);
extern void rels_set_cheapest(List *rel_list); extern void rels_set_cheapest(Query *root, List *rel_list);
extern List *del_rels_all_bushy_inactive(List *old_rels); extern List *del_rels_all_bushy_inactive(List *old_rels);
#endif /* PATHS_H */ #endif /* PATHS_H */
...@@ -6,36 +6,36 @@ ...@@ -6,36 +6,36 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: plancat.h,v 1.14 1999/11/21 23:25:42 tgl Exp $ * $Id: plancat.h,v 1.15 2000/01/09 00:26:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#ifndef PLANCAT_H #ifndef PLANCAT_H
#define PLANCAT_H #define PLANCAT_H
#include "nodes/parsenodes.h" #include "nodes/relation.h"
extern void relation_info(Query *root, Index relid, extern void relation_info(Query *root, Index relid,
bool *hasindex, int *pages, int *tuples); bool *hasindex, long *pages, double *tuples);
extern List *find_secondary_indexes(Query *root, Index relid); extern List *find_secondary_indexes(Query *root, Index relid);
extern Cost restriction_selectivity(Oid functionObjectId, extern List *find_inheritance_children(Oid inhparent);
extern Selectivity restriction_selectivity(Oid functionObjectId,
Oid operatorObjectId, Oid operatorObjectId,
Oid relationObjectId, Oid relationObjectId,
AttrNumber attributeNumber, AttrNumber attributeNumber,
Datum constValue, Datum constValue,
int constFlag); int constFlag);
extern void index_selectivity(Query *root, int relid, Oid indexid, extern void index_selectivity(Query *root, RelOptInfo *rel,
List *indexquals, IndexOptInfo *index, List *indexquals,
float *idxPages, float *idxSelec); long *idxPages, Selectivity *idxSelec);
extern Cost join_selectivity(Oid functionObjectId, Oid operatorObjectId, extern Selectivity join_selectivity(Oid functionObjectId, Oid operatorObjectId,
Oid relationObjectId1, AttrNumber attributeNumber1, Oid relationObjectId1, AttrNumber attributeNumber1,
Oid relationObjectId2, AttrNumber attributeNumber2); Oid relationObjectId2, AttrNumber attributeNumber2);
extern List *find_inheritance_children(Oid inhparent);
#endif /* PLANCAT_H */ #endif /* PLANCAT_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: planmain.h,v 1.34 1999/10/07 04:23:19 tgl Exp $ * $Id: planmain.h,v 1.35 2000/01/09 00:26:47 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,7 +24,7 @@ extern Plan *query_planner(Query *root, List *tlist, List *qual); ...@@ -24,7 +24,7 @@ extern Plan *query_planner(Query *root, List *tlist, List *qual);
/* /*
* prototypes for plan/createplan.c * prototypes for plan/createplan.c
*/ */
extern Plan *create_plan(Path *best_path); extern Plan *create_plan(Query *root, Path *best_path);
extern SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); extern SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
extern Sort *make_sort(List *tlist, Oid nonameid, Plan *lefttree, extern Sort *make_sort(List *tlist, Oid nonameid, Plan *lefttree,
int keycount); int keycount);
...@@ -41,7 +41,6 @@ extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan); ...@@ -41,7 +41,6 @@ extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
extern void make_var_only_tlist(Query *root, List *tlist); extern void make_var_only_tlist(Query *root, List *tlist);
extern void add_restrict_and_join_to_rels(Query *root, List *clauses); extern void add_restrict_and_join_to_rels(Query *root, List *clauses);
extern void add_missing_rels_to_query(Query *root); extern void add_missing_rels_to_query(Query *root);
extern void set_joininfo_mergeable_hashable(List *rel_list);
/* /*
* prototypes for plan/setrefs.c * prototypes for plan/setrefs.c
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment