selfuncs.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,362 行 · 第 1/5 页

C
2,362
字号
		/*		 * Note we assume that each MCV will match at most one member of the		 * other MCV list.	If the operator isn't really equality, there could		 * be multiple matches --- but we don't look for them, both for speed		 * and because the math wouldn't add up...		 */		matchprodfreq = 0.0;		nmatches = 0;		for (i = 0; i < nvalues1; i++)		{			int			j;			for (j = 0; j < nvalues2; j++)			{				if (hasmatch2[j])					continue;				if (DatumGetBool(FunctionCall2(&eqproc,											   values1[i],											   values2[j])))				{					hasmatch1[i] = hasmatch2[j] = true;					matchprodfreq += numbers1[i] * numbers2[j];					nmatches++;					break;				}			}		}		CLAMP_PROBABILITY(matchprodfreq);		/* Sum up frequencies of matched and unmatched MCVs */		matchfreq1 = unmatchfreq1 = 0.0;		for (i = 0; i < nvalues1; i++)		{			if (hasmatch1[i])				matchfreq1 += numbers1[i];			else				unmatchfreq1 += numbers1[i];		}		CLAMP_PROBABILITY(matchfreq1);		CLAMP_PROBABILITY(unmatchfreq1);		matchfreq2 = unmatchfreq2 = 0.0;		for (i = 0; i < nvalues2; i++)		{			if (hasmatch2[i])				matchfreq2 += numbers2[i];			else				unmatchfreq2 += numbers2[i];		}		CLAMP_PROBABILITY(matchfreq2);		CLAMP_PROBABILITY(unmatchfreq2);		pfree(hasmatch1);		pfree(hasmatch2);		/*		 * Compute total frequency of non-null values that are not in the MCV		 * lists.		 */		otherfreq1 = 1.0 - nullfrac1 - matchfreq1 - unmatchfreq1;		otherfreq2 = 1.0 - nullfrac2 - matchfreq2 - unmatchfreq2;		CLAMP_PROBABILITY(otherfreq1);		CLAMP_PROBABILITY(otherfreq2);		/*		 * We can estimate the total selectivity from the point of view of		 * relation 1 as: the known selectivity for matched MCVs, plus		 * unmatched MCVs that are assumed to match against random members of		 * relation 2's non-MCV population, plus non-MCV values that are		 * assumed to match against random members of relation 2's unmatched		 * MCVs plus non-MCV values.		 */		totalsel1 = matchprodfreq;		if (nd2 > nvalues2)			totalsel1 += unmatchfreq1 * otherfreq2 / (nd2 - nvalues2);		if (nd2 > nmatches)			totalsel1 += otherfreq1 * (otherfreq2 + unmatchfreq2) /				(nd2 - nmatches);		/* Same estimate from the point of view of relation 2. */		totalsel2 = matchprodfreq;		if (nd1 > nvalues1)			totalsel2 += unmatchfreq2 * otherfreq1 / (nd1 - nvalues1);		if (nd1 > nmatches)			totalsel2 += otherfreq2 * (otherfreq1 + unmatchfreq1) /				(nd1 - nmatches);		/*		 * Use the smaller of the two estimates.  This can be justified in		 * essentially the same terms as given below for the no-stats case: to		 * a first approximation, we are estimating from the point of view of		 * the relation with smaller nd.		 */		selec = (totalsel1 < totalsel2) ? totalsel1 : totalsel2;	}	else	{		/*		 * We do not have MCV lists for both sides.  Estimate the join		 * selectivity as MIN(1/nd1,1/nd2)*(1-nullfrac1)*(1-nullfrac2). This		 * is plausible if we assume that the join operator is strict and the		 * non-null values are about equally distributed: a given non-null		 * tuple of rel1 will join to either zero or N2*(1-nullfrac2)/nd2 rows		 * of rel2, so total join rows are at most		 * N1*(1-nullfrac1)*N2*(1-nullfrac2)/nd2 giving a join selectivity of		 * not more than (1-nullfrac1)*(1-nullfrac2)/nd2. By the same logic it		 * is not more than (1-nullfrac1)*(1-nullfrac2)/nd1, so the expression		 * with MIN() is an upper bound.  Using the MIN() means we estimate		 * from the point of view of the relation with smaller nd (since the		 * larger nd is determining the MIN).  It is reasonable to assume that		 * most tuples in this rel will have join partners, so the bound is		 * probably reasonably tight and should be taken as-is.		 *		 * XXX Can we be smarter if we have an MCV list for just one side? It		 * seems that if we assume equal distribution for the other side, we		 * end up with the same answer anyway.		 */		double		nullfrac1 = stats1 ? stats1->stanullfrac : 0.0;		double		nullfrac2 = stats2 ? stats2->stanullfrac : 0.0;		selec = (1.0 - nullfrac1) * (1.0 - nullfrac2);		if (nd1 > nd2)			selec /= nd1;		else			selec /= nd2;	}	if (have_mcvs1)		free_attstatsslot(vardata1.atttype, values1, nvalues1,						  numbers1, nnumbers1);	if (have_mcvs2)		free_attstatsslot(vardata2.atttype, values2, nvalues2,						  numbers2, nnumbers2);	ReleaseVariableStats(vardata1);	ReleaseVariableStats(vardata2);	CLAMP_PROBABILITY(selec);	PG_RETURN_FLOAT8((float8) selec);}/* *		neqjoinsel		- Join selectivity of "!=" */Datumneqjoinsel(PG_FUNCTION_ARGS){	PlannerInfo *root = (PlannerInfo *) PG_GETARG_POINTER(0);	Oid			operator = PG_GETARG_OID(1);	List	   *args = (List *) PG_GETARG_POINTER(2);	JoinType	jointype = (JoinType) PG_GETARG_INT16(3);	Oid			eqop;	float8		result;	/*	 * We want 1 - eqjoinsel() where the equality operator is the one	 * associated with this != operator, that is, its negator.	 */	eqop = get_negator(operator);	if (eqop)	{		result = DatumGetFloat8(DirectFunctionCall4(eqjoinsel,													PointerGetDatum(root),													ObjectIdGetDatum(eqop),													PointerGetDatum(args),													Int16GetDatum(jointype)));	}	else	{		/* Use default selectivity (should we raise an error instead?) */		result = DEFAULT_EQ_SEL;	}	result = 1.0 - result;	PG_RETURN_FLOAT8(result);}/* *		scalarltjoinsel - Join selectivity of "<" and "<=" for scalars */Datumscalarltjoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);}/* *		scalargtjoinsel - Join selectivity of ">" and ">=" for scalars */Datumscalargtjoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);}/* * patternjoinsel		- Generic code for pattern-match join selectivity. */static doublepatternjoinsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate){	/* For the moment we just punt. */	return negate ? (1.0 - DEFAULT_MATCH_SEL) : DEFAULT_MATCH_SEL;}/* *		regexeqjoinsel	- Join selectivity of regular-expression pattern match. */Datumregexeqjoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(patternjoinsel(fcinfo, Pattern_Type_Regex, false));}/* *		icregexeqjoinsel	- Join selectivity of case-insensitive regex match. */Datumicregexeqjoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(patternjoinsel(fcinfo, Pattern_Type_Regex_IC, false));}/* *		likejoinsel			- Join selectivity of LIKE pattern match. */Datumlikejoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(patternjoinsel(fcinfo, Pattern_Type_Like, false));}/* *		iclikejoinsel			- Join selectivity of ILIKE pattern match. */Datumiclikejoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(patternjoinsel(fcinfo, Pattern_Type_Like_IC, false));}/* *		regexnejoinsel	- Join selectivity of regex non-match. */Datumregexnejoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(patternjoinsel(fcinfo, Pattern_Type_Regex, true));}/* *		icregexnejoinsel	- Join selectivity of case-insensitive regex non-match. */Datumicregexnejoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(patternjoinsel(fcinfo, Pattern_Type_Regex_IC, true));}/* *		nlikejoinsel		- Join selectivity of LIKE pattern non-match. */Datumnlikejoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(patternjoinsel(fcinfo, Pattern_Type_Like, true));}/* *		icnlikejoinsel		- Join selectivity of ILIKE pattern non-match. */Datumicnlikejoinsel(PG_FUNCTION_ARGS){	PG_RETURN_FLOAT8(patternjoinsel(fcinfo, Pattern_Type_Like_IC, true));}/* * mergejoinscansel			- Scan selectivity of merge join. * * A merge join will stop as soon as it exhausts either input stream. * Therefore, if we can estimate the ranges of both input variables, * we can estimate how much of the input will actually be read.  This * can have a considerable impact on the cost when using indexscans. * * Also, we can estimate how much of each input has to be read before the * first join pair is found, which will affect the join's startup time. * * clause should be a clause already known to be mergejoinable.  opfamily, * strategy, and nulls_first specify the sort ordering being used. * * The outputs are: *		*leftstart is set to the fraction of the left-hand variable expected *		 to be scanned before the first join pair is found (0 to 1). *		*leftend is set to the fraction of the left-hand variable expected *		 to be scanned before the join terminates (0 to 1). *		*rightstart, *rightend similarly for the right-hand variable. */voidmergejoinscansel(PlannerInfo *root, Node *clause,				 Oid opfamily, int strategy, bool nulls_first,				 Selectivity *leftstart, Selectivity *leftend,				 Selectivity *rightstart, Selectivity *rightend){	Node	   *left,			   *right;	VariableStatData leftvar,				rightvar;	int			op_strategy;	Oid			op_lefttype;	Oid			op_righttype;	bool		op_recheck;	Oid			opno,				lsortop,				rsortop,				lstatop,				rstatop,				ltop,				leop,				revltop,				revleop;	bool		isgt;	Datum		leftmin,				leftmax,				rightmin,				rightmax;	double		selec;	/* Set default results if we can't figure anything out. */	/* XXX should default "start" fraction be a bit more than 0? */	*leftstart = *rightstart = 0.0;	*leftend = *rightend = 1.0;	/* Deconstruct the merge clause */	if (!is_opclause(clause))		return;					/* shouldn't happen */	opno = ((OpExpr *) clause)->opno;	left = get_leftop((Expr *) clause);	right = get_rightop((Expr *) clause);	if (!right)		return;					/* shouldn't happen */	/* Look for stats for the inputs */	examine_variable(root, left, 0, &leftvar);	examine_variable(root, right, 0, &rightvar);	/* Extract the operator's declared left/right datatypes */	get_op_opfamily_properties(opno, opfamily,							   &op_strategy,							   &op_lefttype,							   &op_righttype,							   &op_recheck);	Assert(op_strategy == BTEqualStrategyNumber);	Assert(!op_recheck);	/*	 * Look up the various operators we need.  If we don't find them all, it	 * probably means the opfamily is broken, but we just fail silently.	 *	 * Note: we expect that pg_statistic histograms will be sorted by the	 * '<' operator, regardless of which sort direction we are considering.	 */	switch (strategy)	{		case BTLessStrategyNumber:			isgt = false;			if (op_lefttype == op_righttype)			{				/* easy case */				ltop = get_opfamily_member(opfamily,										   op_lefttype, op_righttype,										   BTLessStrategyNumber);				leop = get_opfamily_member(opfamily,										   op_lefttype, op_righttype,										   BTLessEqualStrategyNumber);				lsortop = ltop;				rsortop = ltop;				lstatop = lsortop;				rstatop = rsortop;				revltop = ltop;				revleop = leop;			}			else			{				ltop = get_opfamily_member(opfamily,										   op_lefttype, op_righttype,										   BTLessStrategyNumber);				leop = get_opfamily_member(opfamily,										   op_lefttype, op_righttype,										   BTLessEqualStrategyNumber);				lsortop = get_opfamily_member(opfamily,											  op_lefttype, op_lefttype,											  BTLessStrategyNumber);				rsortop = get_opfamily_member(opfamily,											  op_righttype, op_righttype,											  BTLessStrategyNumber);				lstatop = lsortop;				rstatop = rsortop;				revltop = get_opfamily_member(opfamily,											  op_righttype, op_lefttype,											  BTLessStrategyNumber);				revleop = get_opfamily_member(opfamily,											  op_righttype, op_lefttype,											  BTLessEqualStrategyNumber);			}			break;		case BTGreaterStrategyNumber:			/* descending-order case */			isgt = true;			if (op_lefttype == op_righttype)			{				/* easy case */				ltop = get_opfamily_member(opfamily,										   op_lefttype, op_righttype,										   BTGreaterStrategyNumber);				leop = get_opfamily_member(opfamily,										   op_lefttype, op_righttype,										   BTGreaterEqualStrategyNumber);				lsortop = ltop;				rsortop = ltop;				lstatop = get_opfamily_member(opfamily,											  op_lefttype, op_lefttype,											  BTLessStrategyNumber);				rstatop = lstatop;				revltop = ltop;				revleop = leop;			}			else			{				ltop = get_opfamily_member(opfamily,										   op_lefttype, op_righttype,										   BTGreaterStrategyNumber);				leop = get_opfamily_member(opfamily,										   op_lefttype, op_righttype,										   BTGreaterEqualStrategyNumber);				lsortop = get_opfamily_member(opfamily,											  op_lefttype, op_lefttype,											  BTGreaterStrategyNumber);				rsortop = get_opfamily_member(opfamily,											  op_righttype, op_righttype,											  BTGreaterStrategyNumber);				lstatop = get_opfamily_member(opfamily,											  op_lefttype, op_lefttype,											  BTLessStrategyNumber);				rstatop = get_opfamily_member(opfamily,											  op_righttype, op_righttype,											  BTLessStrategyNumber);				revltop = get_opfamily_member(opfamily,											  op_righttype, op_lefttype,											  BTGreaterStrategyNumber);				revleop = get_opfamily_member(opfamily,											  op_righttype, op_lefttype,											  BTGreaterEqualStrategyNumber);			}			break;		default:			goto fail;			/* shouldn't get here */	}	if (!OidIsValid(lsortop) ||		!OidIsValid(rsortop) ||		!OidIsValid(lstatop) ||		!OidIsValid(rstatop) ||		!OidIsValid(ltop) ||		!OidIsValid(leop) ||		!OidIsValid(revltop) ||		!OidIsValid(revleop))		goto fail;				/* insufficient info in catalogs */	/* Try to get ranges of both inputs */	if (!isgt)	{		if (!get_variable_rang

⌨️ 快捷键说明

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