4949 * Portions Copyright (c) 1994, Regents of the University of California
5050 *
5151 * IDENTIFICATION
52- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.142 2005/04/19 22:35:15 tgl Exp $
52+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.143 2005/04/21 02:28:01 tgl Exp $
5353 *
5454 *-------------------------------------------------------------------------
5555 */
@@ -103,6 +103,7 @@ bool enable_hashjoin = true;
103103
104104
105105static bool cost_qual_eval_walker (Node * node , QualCost * total );
106+ static Selectivity cost_bitmap_qual (Node * bitmapqual , Cost * totalCost );
106107static Selectivity approx_selectivity (Query * root , List * quals ,
107108 JoinType jointype );
108109static Selectivity join_in_selectivity (JoinPath * path , Query * root );
@@ -126,7 +127,7 @@ clamp_row_est(double nrows)
126127 if (nrows < 1.0 )
127128 nrows = 1.0 ;
128129 else
129- nrows = ceil (nrows );
130+ nrows = rint (nrows );
130131
131132 return nrows ;
132133}
@@ -232,6 +233,10 @@ cost_nonsequential_access(double relpages)
232233 * 'is_injoin' is T if we are considering using the index scan as the inside
233234 * of a nestloop join (hence, some of the indexQuals are join clauses)
234235 *
236+ * cost_index() takes an IndexPath not just a Path, because it sets a few
237+ * additional fields of the IndexPath besides startup_cost and total_cost.
238+ * These fields are needed if the IndexPath is used in a BitmapIndexScan.
239+ *
235240 * NOTE: 'indexQuals' must contain only clauses usable as index restrictions.
236241 * Any additional quals evaluated as qpquals may reduce the number of returned
237242 * tuples, but they won't reduce the number of tuples we have to fetch from
@@ -241,7 +246,7 @@ cost_nonsequential_access(double relpages)
241246 * it was a list of bare clause expressions.
242247 */
243248void
244- cost_index (Path * path , Query * root ,
249+ cost_index (IndexPath * path , Query * root ,
245250 IndexOptInfo * index ,
246251 List * indexQuals ,
247252 bool is_injoin )
@@ -286,6 +291,14 @@ cost_index(Path *path, Query *root,
286291 PointerGetDatum (& indexSelectivity ),
287292 PointerGetDatum (& indexCorrelation ));
288293
294+ /*
295+ * Save amcostestimate's results for possible use by cost_bitmap_scan.
296+ * We don't bother to save indexStartupCost or indexCorrelation, because
297+ * a bitmap scan doesn't care about either.
298+ */
299+ path -> indextotalcost = indexTotalCost ;
300+ path -> indexselectivity = indexSelectivity ;
301+
289302 /* all costs for touching index itself included here */
290303 startup_cost += indexStartupCost ;
291304 run_cost += indexTotalCost - indexStartupCost ;
@@ -396,8 +409,8 @@ cost_index(Path *path, Query *root,
396409
397410 run_cost += cpu_per_tuple * tuples_fetched ;
398411
399- path -> startup_cost = startup_cost ;
400- path -> total_cost = startup_cost + run_cost ;
412+ path -> path . startup_cost = startup_cost ;
413+ path -> path . total_cost = startup_cost + run_cost ;
401414}
402415
403416/*
@@ -417,19 +430,151 @@ cost_bitmap_scan(Path *path, Query *root, RelOptInfo *baserel,
417430{
418431 Cost startup_cost = 0 ;
419432 Cost run_cost = 0 ;
433+ Cost indexTotalCost ;
434+ Selectivity indexSelectivity ;
435+ Cost cpu_per_tuple ;
436+ Cost cost_per_page ;
437+ double tuples_fetched ;
438+ double pages_fetched ;
439+ double T ;
420440
421441 /* Should only be applied to base relations */
422442 Assert (IsA (baserel , RelOptInfo ));
423443 Assert (baserel -> relid > 0 );
424444 Assert (baserel -> rtekind == RTE_RELATION );
425445
426- /* XXX lots to do here */
427- run_cost += 10 ;
446+ if (!enable_indexscan ) /* XXX use a separate enable flag? */
447+ startup_cost += disable_cost ;
448+
449+ /*
450+ * Estimate total cost of obtaining the bitmap, as well as its total
451+ * selectivity.
452+ */
453+ indexTotalCost = 0 ;
454+ indexSelectivity = cost_bitmap_qual (bitmapqual , & indexTotalCost );
455+
456+ startup_cost += indexTotalCost ;
457+
458+ /*
459+ * The number of heap pages that need to be fetched is the same as the
460+ * Mackert and Lohman formula for the case T <= b (ie, no re-reads
461+ * needed).
462+ */
463+ tuples_fetched = clamp_row_est (indexSelectivity * baserel -> tuples );
464+
465+ T = (baserel -> pages > 1 ) ? (double ) baserel -> pages : 1.0 ;
466+ pages_fetched = (2.0 * T * tuples_fetched ) / (2.0 * T + tuples_fetched );
467+ if (pages_fetched > T )
468+ pages_fetched = T ;
469+
470+ /*
471+ * For small numbers of pages we should charge random_page_cost apiece,
472+ * while if nearly all the table's pages are being read, it's more
473+ * appropriate to charge 1.0 apiece. The effect is nonlinear, too.
474+ * For lack of a better idea, interpolate like this to determine the
475+ * cost per page.
476+ */
477+ cost_per_page = random_page_cost -
478+ (random_page_cost - 1.0 ) * sqrt (pages_fetched / T );
479+
480+ run_cost += pages_fetched * cost_per_page ;
481+
482+ /*
483+ * Estimate CPU costs per tuple.
484+ *
485+ * Often the indexquals don't need to be rechecked at each tuple ...
486+ * but not always, especially not if there are enough tuples involved
487+ * that the bitmaps become lossy. For the moment, just assume they
488+ * will be rechecked always.
489+ */
490+ startup_cost += baserel -> baserestrictcost .startup ;
491+ cpu_per_tuple = cpu_tuple_cost + baserel -> baserestrictcost .per_tuple ;
492+
493+ run_cost += cpu_per_tuple * tuples_fetched ;
428494
429495 path -> startup_cost = startup_cost ;
430496 path -> total_cost = startup_cost + run_cost ;
431497}
432498
499+ /*
500+ * cost_bitmap_qual
501+ * Recursively examine the AND/OR/IndexPath tree for a bitmap scan
502+ *
503+ * Total execution costs are added to *totalCost (so caller must be sure
504+ * to initialize that to zero). Estimated total selectivity of the bitmap
505+ * is returned as the function result.
506+ */
507+ static Selectivity
508+ cost_bitmap_qual (Node * bitmapqual , Cost * totalCost )
509+ {
510+ Selectivity result ;
511+ Selectivity subresult ;
512+ ListCell * l ;
513+
514+ if (and_clause (bitmapqual ))
515+ {
516+ /*
517+ * We estimate AND selectivity on the assumption that the inputs
518+ * are independent. This is probably often wrong, but we don't
519+ * have the info to do better.
520+ *
521+ * The runtime cost of the BitmapAnd itself is estimated at 100x
522+ * cpu_operator_cost for each tbm_intersect needed. Probably too
523+ * small, definitely too simplistic?
524+ *
525+ * This must agree with make_bitmap_and in createplan.c.
526+ */
527+ result = 1.0 ;
528+ foreach (l , ((BoolExpr * ) bitmapqual )-> args )
529+ {
530+ subresult = cost_bitmap_qual ((Node * ) lfirst (l ), totalCost );
531+ result *= subresult ;
532+ if (l != list_head (((BoolExpr * ) bitmapqual )-> args ))
533+ * totalCost += 100.0 * cpu_operator_cost ;
534+ }
535+ }
536+ else if (or_clause (bitmapqual ))
537+ {
538+ /*
539+ * We estimate OR selectivity on the assumption that the inputs
540+ * are non-overlapping, since that's often the case in "x IN (list)"
541+ * type situations. Of course, we clamp to 1.0 at the end.
542+ *
543+ * The runtime cost of the BitmapOr itself is estimated at 100x
544+ * cpu_operator_cost for each tbm_union needed. Probably too
545+ * small, definitely too simplistic? We are aware that the tbm_unions
546+ * are optimized out when the inputs are BitmapIndexScans.
547+ *
548+ * This must agree with make_bitmap_or in createplan.c.
549+ */
550+ result = 0.0 ;
551+ foreach (l , ((BoolExpr * ) bitmapqual )-> args )
552+ {
553+ subresult = cost_bitmap_qual ((Node * ) lfirst (l ), totalCost );
554+ result += subresult ;
555+ if (l != list_head (((BoolExpr * ) bitmapqual )-> args ) &&
556+ !IsA ((Node * ) lfirst (l ), IndexPath ))
557+ * totalCost += 100.0 * cpu_operator_cost ;
558+ }
559+ result = Min (result , 1.0 );
560+ }
561+ else if (IsA (bitmapqual , IndexPath ))
562+ {
563+ IndexPath * ipath = (IndexPath * ) bitmapqual ;
564+
565+ /* this must agree with create_bitmap_subplan in createplan.c */
566+ * totalCost += ipath -> indextotalcost ;
567+ result = ipath -> indexselectivity ;
568+ }
569+ else
570+ {
571+ elog (ERROR , "unrecognized node type: %d" , nodeTag (bitmapqual ));
572+ result = 0.0 ; /* keep compiler quiet */
573+ }
574+
575+ return result ;
576+ }
577+
433578/*
434579 * cost_tidscan
435580 * Determines and returns the cost of scanning a relation using TIDs.
0 commit comments