costsize.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:12k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * costsize.c
  4.  *   Routines to compute (and set) relation sizes and path costs
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.41.2.1 1999/08/02 06:26:57 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <math.h>
  15. #include "postgres.h"
  16. #ifdef HAVE_LIMITS_H
  17. #include <limits.h>
  18. #ifndef MAXINT
  19. #define MAXINT   INT_MAX
  20. #endif
  21. #else
  22. #ifdef HAVE_VALUES_H
  23. #include <values.h>
  24. #endif
  25. #endif
  26. #include "optimizer/cost.h"
  27. #include "optimizer/internal.h"
  28. #include "optimizer/tlist.h"
  29. #include "utils/lsyscache.h"
  30. extern int NBuffers;
  31. static int compute_attribute_width(TargetEntry *tlistentry);
  32. static double relation_byte_size(int tuples, int width);
  33. static double base_log(double x, double b);
  34. static int compute_targetlist_width(List *targetlist);
  35. int _disable_cost_ = 30000000;
  36. bool _enable_seqscan_ = true;
  37. bool _enable_indexscan_ = true;
  38. bool _enable_sort_ = true;
  39. bool _enable_hash_ = true;
  40. bool _enable_nestloop_ = true;
  41. bool _enable_mergejoin_ = true;
  42. bool _enable_hashjoin_ = true;
  43. Cost  _cpu_page_weight_ = _CPU_PAGE_WEIGHT_;
  44. Cost _cpu_index_page_weight_ = _CPU_INDEX_PAGE_WEIGHT_;
  45. /*
  46.  * cost_seqscan
  47.  *   Determines and returns the cost of scanning a relation sequentially.
  48.  *   If the relation is a temporary to be materialized from a query
  49.  *   embedded within a data field (determined by 'relid' containing an
  50.  *   attribute reference), then a predetermined constant is returned (we
  51.  *   have NO IDEA how big the result of a POSTQUEL procedure is going to
  52.  *   be).
  53.  *
  54.  * disk = p
  55.  * cpu = *CPU-PAGE-WEIGHT* * t
  56.  *
  57.  * 'relid' is the relid of the relation to be scanned
  58.  * 'relpages' is the number of pages in the relation to be scanned
  59.  * (as determined from the system catalogs)
  60.  * 'reltuples' is the number of tuples in the relation to be scanned
  61.  *
  62.  * Returns a flonum.
  63.  *
  64.  */
  65. Cost
  66. cost_seqscan(int relid, int relpages, int reltuples)
  67. {
  68. Cost temp = 0;
  69. if (!_enable_seqscan_)
  70. temp += _disable_cost_;
  71. if (relid < 0)
  72. {
  73. /*
  74.  * cost of sequentially scanning a materialized temporary relation
  75.  */
  76. temp += _NONAME_SCAN_COST_;
  77. }
  78. else
  79. {
  80. temp += relpages;
  81. temp += _cpu_page_weight_ * reltuples;
  82. }
  83. Assert(temp >= 0);
  84. return temp;
  85. }
  86. /*
  87.  * cost_index
  88.  *   Determines and returns the cost of scanning a relation using an index.
  89.  *
  90.  * disk = expected-index-pages + expected-data-pages
  91.  * cpu = *CPU-PAGE-WEIGHT* *
  92.  * (expected-index-tuples + expected-data-tuples)
  93.  *
  94.  * 'indexid' is the index OID
  95.  * 'expected-indexpages' is the number of index pages examined in the scan
  96.  * 'selec' is the selectivity of the index
  97.  * 'relpages' is the number of pages in the main relation
  98.  * 'reltuples' is the number of tuples in the main relation
  99.  * 'indexpages' is the number of pages in the index relation
  100.  * 'indextuples' is the number of tuples in the index relation
  101.  *
  102.  * Returns a flonum.
  103.  *
  104.  */
  105. Cost
  106. cost_index(Oid indexid,
  107.    int expected_indexpages,
  108.    Cost selec,
  109.    int relpages,
  110.    int reltuples,
  111.    int indexpages,
  112.    int indextuples,
  113.    bool is_injoin)
  114. {
  115. Cost temp = 0;
  116. if (!_enable_indexscan_ && !is_injoin)
  117. temp += _disable_cost_;
  118. /*
  119.  * We want to be sure we estimate the cost of an index scan as more
  120.  * than the cost of a sequential scan (when selec == 1.0), even if we
  121.  * don't have good stats.  So, disbelieve zero index size.
  122.  */
  123. if (expected_indexpages <= 0)
  124. expected_indexpages = 1;
  125. if (indextuples <= 0)
  126. indextuples = 1;
  127. /* expected index relation pages */
  128. temp += expected_indexpages;
  129. /*
  130.  * expected base relation pages XXX this isn't really right, since we
  131.  * will access the table nonsequentially and might have to fetch the
  132.  * same page more than once.  This calculation assumes the buffer
  133.  * cache will prevent that from happening...
  134.  */
  135. temp += ceil(((double) selec) * ((double) relpages));
  136. /* per index tuples */
  137. temp += _cpu_index_page_weight_ * selec * indextuples;
  138. /* per heap tuples */
  139. temp += _cpu_page_weight_ * selec * reltuples;
  140. Assert(temp >= 0);
  141. return temp;
  142. }
  143. /*
  144.  * cost_sort
  145.  *   Determines and returns the cost of sorting a relation by considering
  146.  *   the cost of doing an external sort: XXX this is probably too low
  147.  * disk = (p lg p)
  148.  * cpu = *CPU-PAGE-WEIGHT* * (t lg t)
  149.  *
  150.  * 'pathkeys' is a list of sort keys
  151.  * 'tuples' is the number of tuples in the relation
  152.  * 'width' is the average tuple width in bytes
  153.  *
  154.  * NOTE: some callers currently pass NULL for pathkeys because they
  155.  * can't conveniently supply the sort keys.  Since this routine doesn't
  156.  * currently do anything with pathkeys anyway, that doesn't matter...
  157.  * but if it ever does, it should react gracefully to lack of key data.
  158.  *
  159.  * Returns a flonum.
  160.  */
  161. Cost
  162. cost_sort(List *pathkeys, int tuples, int width)
  163. {
  164. Cost temp = 0;
  165. int npages = page_size(tuples, width);
  166. double log_npages;
  167. if (!_enable_sort_)
  168. temp += _disable_cost_;
  169. /*
  170.  * We want to be sure the cost of a sort is never estimated as zero,
  171.  * even if passed-in tuple count is zero.  Besides, mustn't do
  172.  * log(0)...
  173.  */
  174. if (tuples <= 0)
  175. tuples = 1;
  176. if (npages <= 0)
  177. npages = 1;
  178. log_npages = ceil(base_log((double) npages, 2.0));
  179. if (log_npages <= 0.0)
  180. log_npages = 1.0;
  181. temp += npages * log_npages;
  182. /*
  183.  * could be base_log(tuples, NBuffers), but we are only doing 2-way
  184.  * merges
  185.  */
  186. temp += _cpu_page_weight_ * tuples * base_log((double) tuples, 2.0);
  187. Assert(temp > 0);
  188. return temp;
  189. }
  190. /*
  191.  * cost_result
  192.  *   Determines and returns the cost of writing a relation of 'tuples'
  193.  *   tuples of 'width' bytes out to a result relation.
  194.  *
  195.  * Returns a flonum.
  196.  *
  197.  */
  198. #ifdef NOT_USED
  199. Cost
  200. cost_result(int tuples, int width)
  201. {
  202. Cost temp = 0;
  203. temp = temp + page_size(tuples, width);
  204. temp = temp + _cpu_page_weight_ * tuples;
  205. Assert(temp >= 0);
  206. return temp;
  207. }
  208. #endif
  209. /*
  210.  * cost_nestloop
  211.  *   Determines and returns the cost of joining two relations using the
  212.  *   nested loop algorithm.
  213.  *
  214.  * 'outercost' is the (disk+cpu) cost of scanning the outer relation
  215.  * 'innercost' is the (disk+cpu) cost of scanning the inner relation
  216.  * 'outertuples' is the number of tuples in the outer relation
  217.  *
  218.  * Returns a flonum.
  219.  *
  220.  */
  221. Cost
  222. cost_nestloop(Cost outercost,
  223.   Cost innercost,
  224.   int outertuples,
  225.   int innertuples,
  226.   int outerpages,
  227.   bool is_indexjoin)
  228. {
  229. Cost temp = 0;
  230. if (!_enable_nestloop_)
  231. temp += _disable_cost_;
  232. temp += outercost;
  233. temp += outertuples * innercost;
  234. Assert(temp >= 0);
  235. return temp;
  236. }
  237. /*
  238.  * cost_mergejoin
  239.  *   'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
  240.  * outer and inner relations
  241.  *   'outersortkeys' and 'innersortkeys' are lists of the keys to be used
  242.  * to sort the outer and inner relations (or NIL if no explicit
  243.  * sort is needed because the source path is already ordered)
  244.  *   'outertuples' and 'innertuples' are the number of tuples in the outer
  245.  * and inner relations
  246.  *   'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
  247.  * of the tuples of the outer and inner relations
  248.  *
  249.  * Returns a flonum.
  250.  *
  251.  */
  252. Cost
  253. cost_mergejoin(Cost outercost,
  254.    Cost innercost,
  255.    List *outersortkeys,
  256.    List *innersortkeys,
  257.    int outersize,
  258.    int innersize,
  259.    int outerwidth,
  260.    int innerwidth)
  261. {
  262. Cost temp = 0;
  263. if (!_enable_mergejoin_)
  264. temp += _disable_cost_;
  265. temp += outercost;
  266. temp += innercost;
  267. if (outersortkeys) /* do we need to sort? */
  268. temp += cost_sort(outersortkeys, outersize, outerwidth);
  269. if (innersortkeys) /* do we need to sort? */
  270. temp += cost_sort(innersortkeys, innersize, innerwidth);
  271. temp += _cpu_page_weight_ * (outersize + innersize);
  272. Assert(temp >= 0);
  273. return temp;
  274. }
  275. /*
  276.  * cost_hashjoin-- XXX HASH
  277.  *   'outercost' and 'innercost' are the (disk+cpu) costs of scanning the
  278.  * outer and inner relations
  279.  *   'outerkeys' and 'innerkeys' are lists of the keys to be used
  280.  * to hash the outer and inner relations
  281.  *   'outersize' and 'innersize' are the number of tuples in the outer
  282.  * and inner relations
  283.  *   'outerwidth' and 'innerwidth' are the (typical) widths (in bytes)
  284.  * of the tuples of the outer and inner relations
  285.  *
  286.  * Returns a flonum.
  287.  */
  288. Cost
  289. cost_hashjoin(Cost outercost,
  290.   Cost innercost,
  291.   List *outerkeys,
  292.   List *innerkeys,
  293.   int outersize,
  294.   int innersize,
  295.   int outerwidth,
  296.   int innerwidth)
  297. {
  298. Cost temp = 0;
  299. int outerpages = page_size(outersize, outerwidth);
  300. int innerpages = page_size(innersize, innerwidth);
  301. if (!_enable_hashjoin_)
  302. temp += _disable_cost_;
  303. /*
  304.  * Bias against putting larger relation on inside.
  305.  *
  306.  * Code used to use "outerpages < innerpages" but that has poor
  307.  * resolution when both relations are small.
  308.  */
  309. if (relation_byte_size(outersize, outerwidth) <
  310. relation_byte_size(innersize, innerwidth))
  311. temp += _disable_cost_;
  312. /* cost of source data */
  313. temp += outercost + innercost;
  314. /* cost of computing hash function: must do it once per tuple */
  315. temp += _cpu_page_weight_ * (outersize + innersize);
  316. /* cost of main-memory hashtable */
  317. temp += (innerpages < NBuffers) ? innerpages : NBuffers;
  318. /*
  319.  * if inner relation is too big then we will need to "batch" the join,
  320.  * which implies writing and reading most of the tuples to disk an
  321.  * extra time.
  322.  */
  323. if (innerpages > NBuffers)
  324. temp += 2 * (outerpages + innerpages);
  325. Assert(temp >= 0);
  326. return temp;
  327. }
  328. /*
  329.  * compute_rel_size
  330.  *   Computes the size of each relation in 'rel_list' (after applying
  331.  *   restrictions), by multiplying the selectivity of each restriction
  332.  *   by the original size of the relation.
  333.  *
  334.  *   Sets the 'size' field for each relation entry with this computed size.
  335.  *
  336.  * Returns the size.
  337.  */
  338. int
  339. compute_rel_size(RelOptInfo *rel)
  340. {
  341. Cost temp;
  342. int temp1;
  343. temp = rel->tuples * product_selec(rel->restrictinfo);
  344. Assert(temp >= 0);
  345. if (temp >= (MAXINT - 1))
  346. temp1 = MAXINT;
  347. else
  348. temp1 = ceil((double) temp);
  349. Assert(temp1 >= 0);
  350. Assert(temp1 <= MAXINT);
  351. return temp1;
  352. }
  353. /*
  354.  * compute_rel_width
  355.  *   Computes the width in bytes of a tuple from 'rel'.
  356.  *
  357.  * Returns the width of the tuple as a fixnum.
  358.  */
  359. int
  360. compute_rel_width(RelOptInfo *rel)
  361. {
  362. return compute_targetlist_width(get_actual_tlist(rel->targetlist));
  363. }
  364. /*
  365.  * compute_targetlist_width
  366.  *   Computes the width in bytes of a tuple made from 'targetlist'.
  367.  *
  368.  * Returns the width of the tuple as a fixnum.
  369.  */
  370. static int
  371. compute_targetlist_width(List *targetlist)
  372. {
  373. List    *temp_tl;
  374. int tuple_width = 0;
  375. foreach(temp_tl, targetlist)
  376. {
  377. tuple_width = tuple_width +
  378. compute_attribute_width(lfirst(temp_tl));
  379. }
  380. return tuple_width;
  381. }
  382. /*
  383.  * compute_attribute_width
  384.  *   Given a target list entry, find the size in bytes of the attribute.
  385.  *
  386.  *   If a field is variable-length, it is assumed to be at least the size
  387.  *   of a TID field.
  388.  *
  389.  * Returns the width of the attribute as a fixnum.
  390.  */
  391. static int
  392. compute_attribute_width(TargetEntry *tlistentry)
  393. {
  394. int width = get_typlen(tlistentry->resdom->restype);
  395. if (width < 0)
  396. return _DEFAULT_ATTRIBUTE_WIDTH_;
  397. else
  398. return width;
  399. }
  400. /*
  401.  * compute_joinrel_size
  402.  *   Computes the size of the join relation 'joinrel'.
  403.  *
  404.  * Returns a fixnum.
  405.  */
  406. int
  407. compute_joinrel_size(JoinPath *joinpath)
  408. {
  409. Cost temp = 1.0;
  410. int temp1 = 0;
  411. /* cartesian product */
  412. temp *= ((Path *) joinpath->outerjoinpath)->parent->size;
  413. temp *= ((Path *) joinpath->innerjoinpath)->parent->size;
  414. temp = temp * product_selec(joinpath->pathinfo);
  415. if (temp >= (MAXINT - 1) / 2)
  416. {
  417. /* if we exceed (MAXINT-1)/2, we switch to log scale */
  418. /* +1 prevents log(0) */
  419. temp1 = ceil(log(temp + 1 - (MAXINT - 1) / 2) + (MAXINT - 1) / 2);
  420. }
  421. else
  422. temp1 = ceil((double) temp);
  423. Assert(temp1 >= 0);
  424. return temp1;
  425. }
  426. /*
  427.  * relation_byte_size
  428.  *   Estimate the storage space in bytes for a given number of tuples
  429.  *   of a given width (size in bytes).
  430.  *   To avoid overflow with big relations, result is a double.
  431.  */
  432. static double
  433. relation_byte_size(int tuples, int width)
  434. {
  435. return ((double) tuples) * ((double) (width + sizeof(HeapTupleData)));
  436. }
  437. /*
  438.  * page_size
  439.  *   Returns an estimate of the number of pages covered by a given
  440.  *   number of tuples of a given width (size in bytes).
  441.  */
  442. int
  443. page_size(int tuples, int width)
  444. {
  445. int temp;
  446. temp = (int) ceil(relation_byte_size(tuples, width) / BLCKSZ);
  447. Assert(temp >= 0);
  448. return temp;
  449. }
  450. static double
  451. base_log(double x, double b)
  452. {
  453. return log(x) / log(b);
  454. }