Commit 7a7ba335 authored by Tom Lane's avatar Tom Lane

Clean up some bogosities in path cost estimation, like

sometimes estimating an index scan of a table to be cheaper than a
sequential scan of the same tuples...
parent 11a0027e
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.34 1999/04/05 02:07:07 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.35 1999/04/30 04:01:44 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -129,28 +129,36 @@ cost_index(Oid indexid, ...@@ -129,28 +129,36 @@ cost_index(Oid indexid,
int indextuples, int indextuples,
bool is_injoin) bool is_injoin)
{ {
Cost temp; Cost temp = 0;
double temp2;
temp = (Cost) 0;
if (!_enable_indexscan_ && !is_injoin) if (!_enable_indexscan_ && !is_injoin)
temp += _disable_cost_; temp += _disable_cost_;
/* We want to be sure we estimate the cost of an index scan
* as more than the cost of a sequential scan (when selec == 1.0),
* even if we don't have good stats. So, disbelieve zero index size.
*/
if (expected_indexpages <= 0)
expected_indexpages = 1;
if (indextuples <= 0)
indextuples = 1;
/* expected index relation pages */ /* expected index relation pages */
temp += expected_indexpages; temp += expected_indexpages;
/* expected base relation pages */ /* expected base relation pages
temp2 = (reltuples == 0) ? (double) 0 : (double) relpages / reltuples; * XXX this isn't really right, since we will access the table
temp2 = temp2 * (double) selec *indextuples; * nonsequentially and might have to fetch the same page
* more than once. This calculation assumes the buffer cache
temp += Min(relpages, (int) ceil(temp2)); * will prevent that from happening...
*/
temp += ceil(((double) selec) * ((double) relpages));
/* per index tuples */ /* per index tuples */
temp = temp + (_cpu_index_page_wight_ * selec * indextuples); temp += _cpu_index_page_wight_ * selec * indextuples;
/* per heap tuples */ /* per heap tuples */
temp = temp + (_cpu_page_wight_ * selec * reltuples); temp += _cpu_page_wight_ * selec * reltuples;
Assert(temp >= 0); Assert(temp >= 0);
return temp; return temp;
...@@ -168,8 +176,13 @@ cost_index(Oid indexid, ...@@ -168,8 +176,13 @@ cost_index(Oid indexid,
* 'pathkeys' is a list of sort keys * 'pathkeys' is a list of sort keys
* 'tuples' is the number of tuples in the relation * 'tuples' is the number of tuples in the relation
* 'width' is the average tuple width in bytes * 'width' is the average tuple width in bytes
* 'noread' is a flag indicating that the sort result can remain on disk * 'noread' is a flag indicating that the cost of reading the sort
* (i.e., the sort result is the result relation) * source data should not be included (i.e., the caller
* will account for it separately).
*
* NOTE: some callers currently pass NULL for pathkeys because they
* can't conveniently supply sort keys. Since this routine doesn't
* currently do anything with pathkeys anyway, that doesn't matter...
* *
* Returns a flonum. * Returns a flonum.
* *
...@@ -179,28 +192,33 @@ cost_sort(List *pathkeys, int tuples, int width, bool noread) ...@@ -179,28 +192,33 @@ cost_sort(List *pathkeys, int tuples, int width, bool noread)
{ {
Cost temp = 0; Cost temp = 0;
int npages = page_size(tuples, width); int npages = page_size(tuples, width);
Cost pages = (Cost) npages; double log_npages;
Cost numTuples = tuples;
if (!_enable_sort_) if (!_enable_sort_)
temp += _disable_cost_; temp += _disable_cost_;
if (tuples == 0 || pathkeys == NULL)
{ /* We want to be sure the cost of a sort is never estimated as zero,
Assert(temp >= 0); * even if passed-in tuple count is zero. Besides, mustn't do log(0)...
return temp; */
} if (npages <= 0)
temp += pages * base_log((double) pages, (double) 2.0); npages = 1;
log_npages = ceil(base_log((double) npages, 2.0));
if (log_npages <= 0.0)
log_npages = 1.0;
temp += npages * log_npages;
/* /*
* could be base_log(pages, NBuffers), but we are only doing 2-way * could be base_log(pages, NBuffers), but we are only doing 2-way
* merges * merges
*/ */
temp += _cpu_page_wight_ * numTuples * temp += _cpu_page_wight_ * tuples * log_npages;
base_log((double) pages, (double) 2.0);
if (!noread) if (!noread)
temp = temp + cost_seqscan(_NONAME_RELATION_ID_, npages, tuples); temp += cost_seqscan(_NONAME_RELATION_ID_, npages, tuples);
Assert(temp >= 0);
Assert(temp > 0);
return temp; return temp;
} }
...@@ -290,9 +308,12 @@ cost_mergejoin(Cost outercost, ...@@ -290,9 +308,12 @@ cost_mergejoin(Cost outercost,
temp += outercost; temp += outercost;
temp += innercost; temp += innercost;
temp += cost_sort(outersortkeys, outersize, outerwidth, false); if (outersortkeys) /* do we need to sort? */
temp += cost_sort(innersortkeys, innersize, innerwidth, false); temp += cost_sort(outersortkeys, outersize, outerwidth, true);
if (innersortkeys) /* do we need to sort? */
temp += cost_sort(innersortkeys, innersize, innerwidth, true);
temp += _cpu_page_wight_ * (outersize + innersize); temp += _cpu_page_wight_ * (outersize + innersize);
Assert(temp >= 0); Assert(temp >= 0);
return temp; return temp;
......
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