From e91f43a1221b2a810e19a9ab3d3dad37bb7ed168 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 5 Apr 1999 02:07:07 +0000 Subject: [PATCH] Fix potential overflow problems when relation size exceeds 2gig. Fix failure to reliably put the smaller relation on the inside of a hashjoin. --- src/backend/optimizer/path/costsize.c | 57 ++++++++++++++++++--------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index cb30dec42c..c00a9684db 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.33 1999/02/15 03:22:04 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.34 1999/04/05 02:07:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,6 +37,7 @@ extern int NBuffers; static int compute_attribute_width(TargetEntry *tlistentry); +static double relation_byte_size (int tuples, int width); static double base_log(double x, double b); static int compute_targetlist_width(List *targetlist); @@ -323,27 +324,35 @@ cost_hashjoin(Cost outercost, Cost temp = 0; int outerpages = page_size(outersize, outerwidth); int innerpages = page_size(innersize, innerwidth); - int nrun = ceil((double) outerpages / (double) NBuffers); - if (outerpages < innerpages) - return _disable_cost_; if (!_enable_hashjoin_) temp += _disable_cost_; - /* - * temp += outercost + (nrun + 1) * innercost; + /* Bias against putting larger relation on inside. * - * the innercost shouldn't be used it. Instead the cost of hashing the - * innerpath should be used - * - * ASSUME innercost is 1 for now -- a horrible hack - jolly temp += - * outercost + (nrun + 1); - * - * But we must add innercost to result. - vadim 04/24/97 + * Code used to use "outerpages < innerpages" but that has + * poor resolution when both relations are small. */ - temp += outercost + innercost + (nrun + 1); + if (relation_byte_size(outersize, outerwidth) < + relation_byte_size(innersize, innerwidth)) + temp += _disable_cost_; + + /* cost of source data */ + temp += outercost + innercost; + + /* cost of computing hash function: must do it once per tuple */ + temp += _cpu_page_wight_ * (outersize + innersize); + + /* cost of main-memory hashtable */ + temp += (innerpages < NBuffers) ? innerpages : NBuffers; + + /* if inner relation is too big then we will need to "batch" the join, + * which implies writing and reading most of the tuples to disk an + * extra time. + */ + if (innerpages > NBuffers) + temp += 2 * (outerpages + innerpages); - temp += _cpu_page_wight_ * (outersize + nrun * innersize); Assert(temp >= 0); return temp; @@ -458,6 +467,19 @@ compute_joinrel_size(JoinPath *joinpath) return temp1; } +/* + * relation_byte_size + * Estimate the storage space in bytes for a given number of tuples + * of a given width (size in bytes). + * To avoid overflow with big relations, result is a double. + */ + +static double +relation_byte_size (int tuples, int width) +{ + return ((double) tuples) * ((double) (width + sizeof(HeapTupleData))); +} + /* * page_size * Returns an estimate of the number of pages covered by a given @@ -466,10 +488,9 @@ compute_joinrel_size(JoinPath *joinpath) int page_size(int tuples, int width) { - int temp = 0; + int temp; - temp = ceil((double) (tuples * (width + sizeof(HeapTupleData))) - / BLCKSZ); + temp = (int) ceil(relation_byte_size(tuples, width) / BLCKSZ); Assert(temp >= 0); return temp; }