⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 costsize.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * costsize.c *	  Routines to compute (and set) relation sizes and path costs * * Path costs are measured in units of disk accesses: one sequential page * fetch has cost 1.  All else is scaled relative to a page fetch, using * the scaling parameters * *	random_page_cost	Cost of a non-sequential page fetch *	cpu_tuple_cost		Cost of typical CPU time to process a tuple *	cpu_index_tuple_cost  Cost of typical CPU time to process an index tuple *	cpu_operator_cost	Cost of CPU time to process a typical WHERE operator * * We also use a rough estimate "effective_cache_size" of the number of * disk pages in Postgres + OS-level disk cache.  (We can't simply use * NBuffers for this purpose because that would ignore the effects of * the kernel's disk cache.) * * Obviously, taking constants for these values is an oversimplification, * but it's tough enough to get any useful estimates even at this level of * detail.	Note that all of these parameters are user-settable, in case * the default values are drastically off for a particular platform. * * We compute two separate costs for each path: *		total_cost: total estimated cost to fetch all tuples *		startup_cost: cost that is expended before first tuple is fetched * In some scenarios, such as when there is a LIMIT or we are implementing * an EXISTS(...) sub-select, it is not necessary to fetch all tuples of the * path's result.  A caller can estimate the cost of fetching a partial * result by interpolating between startup_cost and total_cost.  In detail: *		actual_cost = startup_cost + *			(total_cost - startup_cost) * tuples_to_fetch / path->parent->rows; * Note that a base relation's rows count (and, by extension, plan_rows for * plan nodes below the LIMIT node) are set without regard to any LIMIT, so * that this equation works properly.  (Also, these routines guarantee not to * set the rows count to zero, so there will be no zero divide.)  The LIMIT is * applied as a top-level plan node. * * For largely historical reasons, most of the routines in this module use * the passed result Path only to store their startup_cost and total_cost * results into.  All the input data they need is passed as separate * parameters, even though much of it could be extracted from the Path. * An exception is made for the cost_XXXjoin() routines, which expect all * the non-cost fields of the passed XXXPath to be filled in. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.149.2.1 2005/11/22 18:23:10 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include <math.h>#include "catalog/pg_statistic.h"#include "executor/nodeHash.h"#include "miscadmin.h"#include "optimizer/clauses.h"#include "optimizer/cost.h"#include "optimizer/pathnode.h"#include "optimizer/plancat.h"#include "parser/parsetree.h"#include "utils/selfuncs.h"#include "utils/lsyscache.h"#include "utils/syscache.h"#define LOG2(x)  (log(x) / 0.693147180559945)#define LOG6(x)  (log(x) / 1.79175946922805)/* * Some Paths return less than the nominal number of rows of their parent * relations; join nodes need to do this to get the correct input count: */#define PATH_ROWS(path) \	(IsA(path, UniquePath) ? \	 ((UniquePath *) (path))->rows : \	 (path)->parent->rows)double		effective_cache_size = DEFAULT_EFFECTIVE_CACHE_SIZE;double		random_page_cost = DEFAULT_RANDOM_PAGE_COST;double		cpu_tuple_cost = DEFAULT_CPU_TUPLE_COST;double		cpu_index_tuple_cost = DEFAULT_CPU_INDEX_TUPLE_COST;double		cpu_operator_cost = DEFAULT_CPU_OPERATOR_COST;Cost		disable_cost = 100000000.0;bool		enable_seqscan = true;bool		enable_indexscan = true;bool		enable_bitmapscan = true;bool		enable_tidscan = true;bool		enable_sort = true;bool		enable_hashagg = true;bool		enable_nestloop = true;bool		enable_mergejoin = true;bool		enable_hashjoin = true;static bool cost_qual_eval_walker(Node *node, QualCost *total);static Selectivity approx_selectivity(PlannerInfo *root, List *quals,				   JoinType jointype);static Selectivity join_in_selectivity(JoinPath *path, PlannerInfo *root);static void set_rel_width(PlannerInfo *root, RelOptInfo *rel);static double relation_byte_size(double tuples, int width);static double page_size(double tuples, int width);/* * clamp_row_est *		Force a row-count estimate to a sane value. */doubleclamp_row_est(double nrows){	/*	 * Force estimate to be at least one row, to make explain output look	 * better and to avoid possible divide-by-zero when interpolating costs.	 * Make it an integer, too.	 */	if (nrows < 1.0)		nrows = 1.0;	else		nrows = rint(nrows);	return nrows;}/* * cost_seqscan *	  Determines and returns the cost of scanning a relation sequentially. */voidcost_seqscan(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 */	Assert(baserel->relid > 0);	Assert(baserel->rtekind == RTE_RELATION);	if (!enable_seqscan)		startup_cost += disable_cost;	/*	 * disk costs	 *	 * The cost of reading a page sequentially is 1.0, by definition. Note	 * that the Unix kernel will typically do some amount of read-ahead	 * optimization, so that this cost is less than the true cost of reading a	 * page from disk.	We ignore that issue here, but must take it into	 * account when estimating the cost of non-sequential accesses!	 */	run_cost += baserel->pages; /* sequential fetches with cost 1.0 */	/* 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_nonsequential_access *	  Estimate the cost of accessing one page at random from a relation *	  (or sort temp file) of the given size in pages. * * The simplistic model that the cost is random_page_cost is what we want * to use for large relations; but for small ones that is a serious * overestimate because of the effects of caching.	This routine tries to * account for that. * * Unfortunately we don't have any good way of estimating the effective cache * size we are working with --- we know that Postgres itself has NBuffers * internal buffers, but the size of the kernel's disk cache is uncertain, * and how much of it we get to use is even less certain.  We punt the problem * for now by assuming we are given an effective_cache_size parameter. * * Given a guesstimated cache size, we estimate the actual I/O cost per page * with the entirely ad-hoc equations (writing relsize for * relpages/effective_cache_size): *	if relsize >= 1: *		random_page_cost - (random_page_cost-1)/2 * (1/relsize) *	if relsize < 1: *		1 + ((random_page_cost-1)/2) * relsize ** 2 * These give the right asymptotic behavior (=> 1.0 as relpages becomes * small, => random_page_cost as it becomes large) and meet in the middle * with the estimate that the cache is about 50% effective for a relation * of the same size as effective_cache_size.  (XXX this is probably all * wrong, but I haven't been able to find any theory about how effective * a disk cache should be presumed to be.) */static Costcost_nonsequential_access(double relpages){	double		relsize;	/* don't crash on bad input data */	if (relpages <= 0.0 || effective_cache_size <= 0.0)		return random_page_cost;	relsize = relpages / effective_cache_size;	if (relsize >= 1.0)		return random_page_cost - (random_page_cost - 1.0) * 0.5 / relsize;	else		return 1.0 + (random_page_cost - 1.0) * 0.5 * relsize * relsize;}/* * cost_index *	  Determines and returns the cost of scanning a relation using an index. * *	  NOTE: an indexscan plan node can actually represent several passes, *	  but here we consider the cost of just one pass. * * 'index' is the index to be used * 'indexQuals' is the list of applicable qual clauses (implicit AND semantics) * 'is_injoin' is T if we are considering using the index scan as the inside *		of a nestloop join (hence, some of the indexQuals are join clauses) * * cost_index() takes an IndexPath not just a Path, because it sets a few * additional fields of the IndexPath besides startup_cost and total_cost. * These fields are needed if the IndexPath is used in a BitmapIndexScan. * * NOTE: 'indexQuals' must contain only clauses usable as index restrictions. * Any additional quals evaluated as qpquals may reduce the number of returned * tuples, but they won't reduce the number of tuples we have to fetch from * the table, so they don't reduce the scan cost. * * NOTE: as of 8.0, indexQuals is a list of RestrictInfo nodes, where formerly * it was a list of bare clause expressions. */voidcost_index(IndexPath *path, PlannerInfo *root,		   IndexOptInfo *index,		   List *indexQuals,		   bool is_injoin){	RelOptInfo *baserel = index->rel;	Cost		startup_cost = 0;	Cost		run_cost = 0;	Cost		indexStartupCost;	Cost		indexTotalCost;	Selectivity indexSelectivity;	double		indexCorrelation,				csquared;	Cost		min_IO_cost,				max_IO_cost;	Cost		cpu_per_tuple;	double		tuples_fetched;	double		pages_fetched;	double		T,				b;	/* Should only be applied to base relations */	Assert(IsA(baserel, RelOptInfo) &&		   IsA(index, IndexOptInfo));	Assert(baserel->relid > 0);	Assert(baserel->rtekind == RTE_RELATION);	if (!enable_indexscan)		startup_cost += disable_cost;	/*	 * Call index-access-method-specific code to estimate the processing cost	 * for scanning the index, as well as the selectivity of the index (ie,	 * the fraction of main-table tuples we will have to retrieve) and its	 * correlation to the main-table tuple order.	 */	OidFunctionCall7(index->amcostestimate,					 PointerGetDatum(root),					 PointerGetDatum(index),					 PointerGetDatum(indexQuals),					 PointerGetDatum(&indexStartupCost),					 PointerGetDatum(&indexTotalCost),					 PointerGetDatum(&indexSelectivity),					 PointerGetDatum(&indexCorrelation));	/*	 * Save amcostestimate's results for possible use in bitmap scan planning.	 * We don't bother to save indexStartupCost or indexCorrelation, because a	 * bitmap scan doesn't care about either.	 */	path->indextotalcost = indexTotalCost;	path->indexselectivity = indexSelectivity;	/* all costs for touching index itself included here */	startup_cost += indexStartupCost;	run_cost += indexTotalCost - indexStartupCost;	/*----------	 * Estimate number of main-table tuples and pages fetched.	 *	 * When the index ordering is uncorrelated with the table ordering,	 * we use an approximation proposed by Mackert and Lohman, "Index Scans	 * Using a Finite LRU Buffer: A Validated I/O Model", ACM Transactions	 * on Database Systems, Vol. 14, No. 3, September 1989, Pages 401-424.	 * The Mackert and Lohman approximation is that the number of pages	 * fetched is	 *	PF =	 *		min(2TNs/(2T+Ns), T)			when T <= b	 *		2TNs/(2T+Ns)					when T > b and Ns <= 2Tb/(2T-b)	 *		b + (Ns - 2Tb/(2T-b))*(T-b)/T	when T > b and Ns > 2Tb/(2T-b)	 * where	 *		T = # pages in table	 *		N = # tuples in table	 *		s = selectivity = fraction of table to be scanned	 *		b = # buffer pages available (we include kernel space here)	 *	 * When the index ordering is exactly correlated with the table ordering	 * (just after a CLUSTER, for example), the number of pages fetched should	 * be just sT.	What's more, these will be sequential fetches, not the	 * random fetches that occur in the uncorrelated case.	So, depending on	 * the extent of correlation, we should estimate the actual I/O cost	 * somewhere between s * T * 1.0 and PF * random_cost.	We currently	 * interpolate linearly between these two endpoints based on the	 * correlation squared (XXX is that appropriate?).	 *	 * In any case the number of tuples fetched is Ns.	 *----------	 */	tuples_fetched = clamp_row_est(indexSelectivity * baserel->tuples);	/* This part is the Mackert and Lohman formula */	T = (baserel->pages > 1) ? (double) baserel->pages : 1.0;	b = (effective_cache_size > 1) ? effective_cache_size : 1.0;	if (T <= b)	{		pages_fetched =			(2.0 * T * tuples_fetched) / (2.0 * T + tuples_fetched);		if (pages_fetched > T)			pages_fetched = T;	}	else	{		double		lim;		lim = (2.0 * T * b) / (2.0 * T - b);		if (tuples_fetched <= lim)		{			pages_fetched =				(2.0 * T * tuples_fetched) / (2.0 * T + tuples_fetched);		}		else		{			pages_fetched =				b + (tuples_fetched - lim) * (T - b) / T;		}	}	/*	 * min_IO_cost corresponds to the perfectly correlated case (csquared=1),	 * max_IO_cost to the perfectly uncorrelated case (csquared=0).  Note that	 * we just charge random_page_cost per page in the uncorrelated case,	 * rather than using cost_nonsequential_access, since we've already	 * accounted for caching effects by using the Mackert model.	 */	min_IO_cost = ceil(indexSelectivity * T);	max_IO_cost = pages_fetched * random_page_cost;	/*	 * Now interpolate based on estimated index order correlation to get total	 * disk I/O cost for main table accesses.	 */	csquared = indexCorrelation * indexCorrelation;	run_cost += max_IO_cost + csquared * (min_IO_cost - max_IO_cost);	/*	 * Estimate CPU costs per tuple.	 *	 * Normally the indexquals will be removed from the list of restriction	 * clauses that we have to evaluate as qpquals, so we should subtract	 * their costs from baserestrictcost.  But if we are doing a join then	 * some of the indexquals are join clauses and shouldn't be subtracted.	 * Rather than work out exactly how much to subtract, we don't subtract	 * anything.	 */	startup_cost += baserel->baserestrictcost.startup;	cpu_per_tuple = cpu_tuple_cost + baserel->baserestrictcost.per_tuple;	if (!is_injoin)	{		QualCost	index_qual_cost;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -