costsize.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,000 行 · 第 1/5 页
C
2,000 行
cost_qual_eval(&index_qual_cost, indexQuals); /* any startup cost still has to be paid ... */ cpu_per_tuple -= index_qual_cost.per_tuple; } run_cost += cpu_per_tuple * tuples_fetched; path->path.startup_cost = startup_cost; path->path.total_cost = startup_cost + run_cost;}/* * cost_bitmap_heap_scan * Determines and returns the cost of scanning a relation using a bitmap * index-then-heap plan. * * 'baserel' is the relation to be scanned * 'bitmapqual' is a tree of IndexPaths, BitmapAndPaths, and BitmapOrPaths * 'is_injoin' is T if we are considering using the scan as the inside * of a nestloop join (hence, some of the quals are join clauses) */voidcost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel, Path *bitmapqual, bool is_injoin){ Cost startup_cost = 0; Cost run_cost = 0; Cost indexTotalCost; Selectivity indexSelectivity; Cost cpu_per_tuple; Cost cost_per_page; double tuples_fetched; double pages_fetched; double T; /* Should only be applied to base relations */ Assert(IsA(baserel, RelOptInfo)); Assert(baserel->relid > 0); Assert(baserel->rtekind == RTE_RELATION); if (!enable_bitmapscan) startup_cost += disable_cost; /* * Fetch total cost of obtaining the bitmap, as well as its total * selectivity. */ cost_bitmap_tree_node(bitmapqual, &indexTotalCost, &indexSelectivity); startup_cost += indexTotalCost; /* * The number of heap pages that need to be fetched is the same as the * Mackert and Lohman formula for the case T <= b (ie, no re-reads * needed). */ tuples_fetched = clamp_row_est(indexSelectivity * baserel->tuples); T = (baserel->pages > 1) ? (double) baserel->pages : 1.0; pages_fetched = (2.0 * T * tuples_fetched) / (2.0 * T + tuples_fetched); if (pages_fetched > T) pages_fetched = T; /* * For small numbers of pages we should charge random_page_cost apiece, * while if nearly all the table's pages are being read, it's more * appropriate to charge 1.0 apiece. The effect is nonlinear, too. For * lack of a better idea, interpolate like this to determine the cost per * page. */ if (pages_fetched >= 2.0) cost_per_page = random_page_cost - (random_page_cost - 1.0) * sqrt(pages_fetched / T); else cost_per_page = random_page_cost; run_cost += pages_fetched * cost_per_page; /* * Estimate CPU costs per tuple. * * Often the indexquals don't need to be rechecked at each tuple ... but * not always, especially not if there are enough tuples involved that the * bitmaps become lossy. For the moment, just assume they will be * rechecked always. */ startup_cost += baserel->baserestrictcost.startup; cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple; run_cost += cpu_per_tuple * tuples_fetched; path->startup_cost = startup_cost; path->total_cost = startup_cost + run_cost;}/* * cost_bitmap_tree_node * Extract cost and selectivity from a bitmap tree node (index/and/or) */voidcost_bitmap_tree_node(Path *path, Cost *cost, Selectivity *selec){ if (IsA(path, IndexPath)) { *cost = ((IndexPath *) path)->indextotalcost; *selec = ((IndexPath *) path)->indexselectivity; } else if (IsA(path, BitmapAndPath)) { *cost = path->total_cost; *selec = ((BitmapAndPath *) path)->bitmapselectivity; } else if (IsA(path, BitmapOrPath)) { *cost = path->total_cost; *selec = ((BitmapOrPath *) path)->bitmapselectivity; } else elog(ERROR, "unrecognized node type: %d", nodeTag(path));}/* * cost_bitmap_and_node * Estimate the cost of a BitmapAnd node * * Note that this considers only the costs of index scanning and bitmap * creation, not the eventual heap access. In that sense the object isn't * truly a Path, but it has enough path-like properties (costs in particular) * to warrant treating it as one. */voidcost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root){ Cost totalCost; Selectivity selec; ListCell *l; /* * We estimate AND selectivity on the assumption that the inputs are * independent. This is probably often wrong, but we don't have the info * to do better. * * The runtime cost of the BitmapAnd itself is estimated at 100x * cpu_operator_cost for each tbm_intersect needed. Probably too small, * definitely too simplistic? */ totalCost = 0.0; selec = 1.0; foreach(l, path->bitmapquals) { Path *subpath = (Path *) lfirst(l); Cost subCost; Selectivity subselec; cost_bitmap_tree_node(subpath, &subCost, &subselec); selec *= subselec; totalCost += subCost; if (l != list_head(path->bitmapquals)) totalCost += 100.0 * cpu_operator_cost; } path->bitmapselectivity = selec; path->path.startup_cost = totalCost; path->path.total_cost = totalCost;}/* * cost_bitmap_or_node * Estimate the cost of a BitmapOr node * * See comments for cost_bitmap_and_node. */voidcost_bitmap_or_node(BitmapOrPath *path, PlannerInfo *root){ Cost totalCost; Selectivity selec; ListCell *l; /* * We estimate OR selectivity on the assumption that the inputs are * non-overlapping, since that's often the case in "x IN (list)" type * situations. Of course, we clamp to 1.0 at the end. * * The runtime cost of the BitmapOr itself is estimated at 100x * cpu_operator_cost for each tbm_union needed. Probably too small, * definitely too simplistic? We are aware that the tbm_unions are * optimized out when the inputs are BitmapIndexScans. */ totalCost = 0.0; selec = 0.0; foreach(l, path->bitmapquals) { Path *subpath = (Path *) lfirst(l); Cost subCost; Selectivity subselec; cost_bitmap_tree_node(subpath, &subCost, &subselec); selec += subselec; totalCost += subCost; if (l != list_head(path->bitmapquals) && !IsA(subpath, IndexPath)) totalCost += 100.0 * cpu_operator_cost; } path->bitmapselectivity = Min(selec, 1.0); path->path.startup_cost = totalCost; path->path.total_cost = totalCost;}/* * cost_tidscan * Determines and returns the cost of scanning a relation using TIDs. */voidcost_tidscan(Path *path, PlannerInfo *root, RelOptInfo *baserel, List *tideval){ Cost startup_cost = 0; Cost run_cost = 0; Cost cpu_per_tuple; int ntuples = list_length(tideval); /* Should only be applied to base relations */ Assert(baserel->relid > 0); Assert(baserel->rtekind == RTE_RELATION); if (!enable_tidscan) startup_cost += disable_cost; /* disk costs --- assume each tuple on a different page */ run_cost += random_page_cost * ntuples; /* CPU costs */ startup_cost += baserel->baserestrictcost.startup; cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple; run_cost += cpu_per_tuple * ntuples; path->startup_cost = startup_cost; path->total_cost = startup_cost + run_cost;}/* * cost_subqueryscan * Determines and returns the cost of scanning a subquery RTE. */voidcost_subqueryscan(Path *path, RelOptInfo *baserel){ Cost startup_cost; Cost run_cost; Cost cpu_per_tuple; /* Should only be applied to base relations that are subqueries */ Assert(baserel->relid > 0); Assert(baserel->rtekind == RTE_SUBQUERY); /* * Cost of path is cost of evaluating the subplan, plus cost of evaluating * any restriction clauses that will be attached to the SubqueryScan node, * plus cpu_tuple_cost to account for selection and projection overhead. */ path->startup_cost = baserel->subplan->startup_cost; path->total_cost = baserel->subplan->total_cost; startup_cost = baserel->baserestrictcost.startup; cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple; run_cost = cpu_per_tuple * baserel->tuples; path->startup_cost += startup_cost; path->total_cost += startup_cost + run_cost;}/* * cost_functionscan * Determines and returns the cost of scanning a function RTE. */voidcost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel){ Cost startup_cost = 0; Cost run_cost = 0; Cost cpu_per_tuple; /* Should only be applied to base relations that are functions */ Assert(baserel->relid > 0); Assert(baserel->rtekind == RTE_FUNCTION); /* * For now, estimate function's cost at one operator eval per function * call. Someday we should revive the function cost estimate columns in * pg_proc... */ cpu_per_tuple = cpu_operator_cost; /* Add scanning CPU costs */ startup_cost += baserel->baserestrictcost.startup; cpu_per_tuple += cpu_tuple_cost + baserel->baserestrictcost.per_tuple; run_cost += cpu_per_tuple * baserel->tuples; path->startup_cost = startup_cost; path->total_cost = startup_cost + run_cost;}/* * cost_sort * Determines and returns the cost of sorting a relation, including * the cost of reading the input data. * * If the total volume of data to sort is less than work_mem, we will do * an in-memory sort, which requires no I/O and about t*log2(t) tuple * comparisons for t tuples. * * If the total volume exceeds work_mem, we switch to a tape-style merge * algorithm. There will still be about t*log2(t) tuple comparisons in * total, but we will also need to write and read each tuple once per * merge pass. We expect about ceil(log6(r)) merge passes where r is the * number of initial runs formed (log6 because tuplesort.c uses six-tape * merging). Since the average initial run should be about twice work_mem, * we have * disk traffic = 2 * relsize * ceil(log6(p / (2*work_mem))) * cpu = comparison_cost * t * log2(t) * * The disk traffic is assumed to be half sequential and half random * accesses (XXX can't we refine that guess?) * * We charge two operator evals per tuple comparison, which should be in * the right ballpark in most cases. * * 'pathkeys' is a list of sort keys * 'input_cost' is the total cost for reading the input data * 'tuples' is the number of tuples in the relation * 'width' is the average tuple width in bytes * * NOTE: some callers currently pass NIL for pathkeys because they * can't conveniently supply the sort keys. Since this routine doesn't * currently do anything with pathkeys anyway, that doesn't matter... * but if it ever does, it should react gracefully to lack of key data. * (Actually, the thing we'd most likely be interested in is just the number * of sort keys, which all callers *could* supply.) */voidcost_sort(Path *path, PlannerInfo *root, List *pathkeys, Cost input_cost, double tuples, int width){ Cost startup_cost = input_cost; Cost run_cost = 0; double nbytes = relation_byte_size(tuples, width); long work_mem_bytes = work_mem * 1024L; if (!enable_sort) startup_cost += disable_cost; /* * We want to be sure the cost of a sort is never estimated as zero, even * if passed-in tuple count is zero. Besides, mustn't do log(0)... */ if (tuples < 2.0) tuples = 2.0; /* * CPU costs * * Assume about two operator evals per tuple comparison and N log2 N * comparisons */ startup_cost += 2.0 * cpu_operator_cost * tuples * LOG2(tuples); /* disk costs */ if (nbytes > work_mem_bytes) { double npages = ceil(nbytes / BLCKSZ); double nruns = (nbytes / work_mem_bytes) * 0.5; double log_runs = ceil(LOG6(nruns)); double npageaccesses; if (log_runs < 1.0) log_runs = 1.0; npageaccesses = 2.0 * npages * log_runs; /* Assume half are sequential (cost 1), half are not */ startup_cost += npageaccesses * (1.0 + cost_nonsequential_access(npages)) * 0.5; } /* * Also charge a small amount (arbitrarily set equal to operator cost) per * extracted tuple. */ run_cost += cpu_operator_cost * tuples; path->startup_cost = startup_cost; path->total_cost = startup_cost + run_cost;}/* * cost_material * Determines and returns the cost of materializing a relation, including
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?