/* size of the struct header fields (magic, type, ndeps) */ #define SizeOfHeader (3 * sizeof(uint32))
/* size of a serialized dependency (degree, natts, atts) */ #define SizeOfItem(natts) \
(sizeof(double) + sizeof(AttrNumber) * (1 + (natts)))
/* minimal size of a dependency (with two attributes) */ #define MinSizeOfItem SizeOfItem(2)
/* minimal size of dependencies, when all deps are minimal */ #define MinSizeOfItems(ndeps) \
(SizeOfHeader + (ndeps) * MinSizeOfItem)
/* *InternalstateforDependencyGeneratorofdependencies.Dependenciesaresimilarto *k-permutationsofnelements,exceptthattheorderdoesnotmatterforthe *first(k-1)elements.Thatis,(a,b=>c)and(b,a=>c)areequivalent.
*/ typedefstruct DependencyGeneratorData
{ int k; /* size of the dependency */ int n; /* number of possible attributes */ int current; /* next dependency to return (index) */
AttrNumber ndependencies; /* number of dependencies generated */
AttrNumber *dependencies; /* array of pre-generated dependencies */
} DependencyGeneratorData;
/* prepare the sort function for the dimensions */ for (i = 0; i < k; i++)
{
VacAttrStats *colstat = data->stats[dependency[i]];
TypeCacheEntry *type;
type = lookup_type_cache(colstat->attrtypid, TYPECACHE_LT_OPR); if (type->lt_opr == InvalidOid) /* shouldn't happen */
elog(ERROR, "cache lookup failed for ordering operator for type %u",
colstat->attrtypid);
/* prepare the sort function for this dimension */
multi_sort_add_dimension(mss, i, type->lt_opr, colstat->attrcollid);
}
/* start with the first row forming a group */
group_size = 1;
/* loop 1 beyond the end of the array so that we count the final group */ for (i = 1; i <= nitems; i++)
{ /* *Checkifthegroupended,whichmaybeeitherbecauseweprocessed *alltheitems(i==nitems),orbecausethei-thitemisnotequalto *theprecedingone.
*/ if (i == nitems ||
multi_sort_compare_dims(0, k - 2, &items[i - 1], &items[i], mss) != 0)
{ /* *Ifnoviolationswerefoundinthegroupthentracktherowsof *thegroupassupportingthefunctionaldependency.
*/ if (n_violations == 0)
n_supporting_rows += group_size;
/* Reset counters for the new group */
n_violations = 0;
group_size = 1; continue;
} /* first columns match, but the last one does not (so contradicting) */ elseif (multi_sort_compare_dim(k - 1, &items[i - 1], &items[i], mss) != 0)
n_violations++;
group_size++;
}
/* Compute the 'degree of validity' as (supporting/total). */ return (n_supporting_rows * 1.0 / data->numrows);
}
/* *We'lltrybuildfunctionaldependenciesstartingfromthesmallestones *coveringjust2columns,tothelargestones,coveringallcolumns *includedinthestatisticsobject.Westartfromthesmallestones *becausewewanttobeabletoskipalreadyimpliedones.
*/ for (k = 2; k <= data->nattnums; k++)
{
AttrNumber *dependency; /* array with k elements */
/* prepare a DependencyGenerator of variation */
DependencyGenerator DependencyGenerator = DependencyGenerator_init(data->nattnums, k);
/* generate all possible variations of k values (out of n) */ while ((dependency = DependencyGenerator_next(DependencyGenerator)))
{ double degree;
MVDependency *d;
MemoryContext oldcxt;
/* release memory used by dependency degree calculation */
oldcxt = MemoryContextSwitchTo(cxt);
/* compute how valid the dependency seems */
degree = dependency_degree(data, k, dependency);
/* *ifthedependencyseemsentirelyinvalid,don'tstoreit
*/ if (degree == 0.0) continue;
d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
+ k * sizeof(AttrNumber));
/* copy the dependency (and keep the indexes into stxkeys) */
d->degree = degree;
d->nattributes = k; for (i = 0; i < k; i++)
d->attributes[i] = data->attnums[dependency[i]];
/* initialize the list of dependencies */ if (dependencies == NULL)
{
dependencies
= (MVDependencies *) palloc0(sizeof(MVDependencies));
/* we need to store ndeps, with a number of attributes for each one */
len = VARHDRSZ + SizeOfHeader;
/* and also include space for the actual attribute numbers and degrees */ for (i = 0; i < dependencies->ndeps; i++)
len += SizeOfItem(dependencies->deps[i]->nattributes);
/* Store the base struct values (magic, type, ndeps) */
memcpy(tmp, &dependencies->magic, sizeof(uint32));
tmp += sizeof(uint32);
memcpy(tmp, &dependencies->type, sizeof(uint32));
tmp += sizeof(uint32);
memcpy(tmp, &dependencies->ndeps, sizeof(uint32));
tmp += sizeof(uint32);
/* store number of attributes and attribute numbers for each dependency */ for (i = 0; i < dependencies->ndeps; i++)
{
MVDependency *d = dependencies->deps[i];
if (VARSIZE_ANY_EXHDR(data) < SizeOfHeader)
elog(ERROR, "invalid MVDependencies size %zu (expected at least %zu)",
VARSIZE_ANY_EXHDR(data), SizeOfHeader);
if (dependencies->type != STATS_DEPS_TYPE_BASIC)
elog(ERROR, "invalid dependency type %d (expected %d)",
dependencies->type, STATS_DEPS_TYPE_BASIC);
if (dependencies->ndeps == 0)
elog(ERROR, "invalid zero-length item array in MVDependencies");
/* what minimum bytea size do we expect for those parameters */
min_expected_size = SizeOfItem(dependencies->ndeps);
if (VARSIZE_ANY_EXHDR(data) < min_expected_size)
elog(ERROR, "invalid dependencies size %zu (expected at least %zu)",
VARSIZE_ANY_EXHDR(data), min_expected_size);
/* allocate space for the MCV items */
dependencies = repalloc(dependencies, offsetof(MVDependencies, deps)
+ (dependencies->ndeps * sizeof(MVDependency *)));
for (i = 0; i < dependencies->ndeps; i++)
{ double degree;
AttrNumber k;
MVDependency *d;
/* number of attributes */
memcpy(&k, tmp, sizeof(AttrNumber));
tmp += sizeof(AttrNumber);
/* is the number of attributes valid? */
Assert((k >= 2) && (k <= STATS_MAX_DIMENSIONS));
/* now that we know the number of attributes, allocate the dependency */
d = (MVDependency *) palloc0(offsetof(MVDependency, attributes)
+ (k * sizeof(AttrNumber)));
htup = SearchSysCache2(STATEXTDATASTXOID,
ObjectIdGetDatum(mvoid),
BoolGetDatum(inh)); if (!HeapTupleIsValid(htup))
elog(ERROR, "cache lookup failed for statistics object %u", mvoid);
deps = SysCacheGetAttr(STATEXTDATASTXOID, htup,
Anum_pg_statistic_ext_data_stxddependencies, &isnull); if (isnull)
elog(ERROR, "requested statistics kind \"%c\" is not yet built for statistics object %u",
STATS_EXT_DEPENDENCIES, mvoid);
result = statext_dependencies_deserialize(DatumGetByteaPP(deps));
ReleaseSysCache(htup);
return result;
}
/* *pg_dependencies_in-inputroutinefortypepg_dependencies. * *pg_dependenciesisrealenoughtobeatablecolumn,butithasnooperations *ofitsown,anddisallowsinputtoo
*/
Datum
pg_dependencies_in(PG_FUNCTION_ARGS)
{ /* *pg_node_liststoresthedatainbinaryformandparsingtextinputis *notneeded,sodisallowthis.
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_dependencies")));
PG_RETURN_VOID(); /* keep compiler quiet */
}
/* *pg_dependencies-outputroutinefortypepg_dependencies.
*/
Datum
pg_dependencies_out(PG_FUNCTION_ARGS)
{
bytea *data = PG_GETARG_BYTEA_PP(0);
MVDependencies *dependencies = statext_dependencies_deserialize(data); int i,
j;
StringInfoData str;
/* *pg_dependencies_recv-binaryinputroutinefortypepg_dependencies.
*/
Datum
pg_dependencies_recv(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot accept a value of type %s", "pg_dependencies")));
/* OK to proceed with checking "var" */
} elseif (IsA(clause, ScalarArrayOpExpr))
{ /* If it's a scalar array operator, check for Var IN Const. */
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
/* *RejectALL()variant,weonlycareaboutANY/IN. * *XXXMaybeweshouldcheckifallthevaluesarethesame,andallow *ALLinthatcase?Doesn'tseemverypractical,though.
*/ if (!expr->useOr) returnfalse;
/* Only expressions with two arguments are candidates. */ if (list_length(expr->args) != 2) returnfalse;
/* *Weknowit'salways(VarINConst),soweassumethevaristhe *firstargument,andpseudoconstantisthesecondone.
*/ if (!is_pseudo_constant_clause(lsecond(expr->args))) returnfalse;
/* number of attnums in clauses */ int nattnums = bms_num_members(attnums);
/* *IterateovertheMVDependencyitemsandfindthestrongestonefromthe *fully-matcheddependencies.Wedothecheapchecksfirst,before *matchingitagainsttheattnums.
*/ for (i = 0; i < ndependencies; i++)
{ for (j = 0; j < dependencies[i]->ndeps; j++)
{
MVDependency *dependency = dependencies[i]->deps[j];
/* *Skipdependenciesreferencingmoreattributesthanavailable *clauses,asthosecan'tbefullymatched.
*/ if (dependency->nattributes > nattnums) continue;
if (strongest)
{ /* skip dependencies on fewer attributes than the strongest. */ if (dependency->nattributes < strongest->nattributes) continue;
/* also skip weaker dependencies when attribute count matches */ if (strongest->nattributes == dependency->nattributes &&
strongest->degree > dependency->degree) continue;
}
/* *thisdependencyisstronger,butwemuststillcheckthatit's *fullymatchedtotheseattnums.Weperformthischecklastas *it'sslightlymoreexpensivethanthepreviouschecks.
*/ if (dependency_is_fully_matched(dependency, attnums))
strongest = dependency; /* save new best match */
}
}
return strongest;
}
/* *clauselist_apply_dependencies *Applythespecifiedfunctionaldependenciestoalistofclausesand *returntheestimatedselectivityoftheclausesthatarecompatible *withanyofthegivendependencies. * *Thiswillestimateallnot-already-estimatedclausesthatarecompatible *withfunctionaldependencies,andwhichhaveanattributementionedbyany *ofthegivendependencies(eitherasanimplyingorimpliedattribute). * *Given(listsof)clausesonattributes(a,b)andafunctionaldependency *(a=>b),theper-columnselectivitiesP(a)andP(b)arenotionallycombined *usingtheformula * *P(a,b)=f*P(a)+(1-f)*P(a)*P(b) * *where'f'isthedegreeofdependency.Thisreflectsthefactthatwe *expectafractionfofallrowstobeconsistentwiththedependency *(a=>b),andsohaveaselectivityofP(a),whiletheremainingrowsare *treatedasindependent. * *Inpractice,weuseaslightlymodifiedversionofthisformula,whichuses *aselectivityofMin(P(a),P(b))forthedependentrows,sincetheresult *shouldobviouslynotexceedeithercolumn'sindividualselectivity.I.e., *weactuallycombineselectivitiesusingtheformula * *P(a,b)=f*Min(P(a),P(b))+(1-f)*P(a)*P(b) * *Thiscanmakequiteadifferenceifthespecificvaluesmatchingthe *clausesarenotconsistentwiththefunctionaldependency.
*/ static Selectivity
clauselist_apply_dependencies(PlannerInfo *root, List *clauses, int varRelid, JoinType jointype,
SpecialJoinInfo *sjinfo,
MVDependency **dependencies, int ndependencies,
AttrNumber *list_attnums,
Bitmapset **estimatedclauses)
{
Bitmapset *attnums; int i; int j; int nattrs;
Selectivity *attr_sel; int attidx; int listidx;
ListCell *l;
Selectivity s1;
/* *Extracttheattnumsofallimplyingandimpliedattributesfromallthe *givendependencies.Eachoftheseattributesisexpectedtohaveat *least1not-already-estimatedcompatibleclausethatwewillestimate *here.
*/
attnums = NULL; for (i = 0; i < ndependencies; i++)
{ for (j = 0; j < dependencies[i]->nattributes; j++)
{
AttrNumber attnum = dependencies[i]->attributes[j];
/* OK to proceed with checking "var" */
} elseif (IsA(clause, ScalarArrayOpExpr))
{ /* If it's a scalar array operator, check for Var IN Const. */
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) clause;
/* *RejectALL()variant,weonlycareaboutANY/IN. * *FIXMEMaybeweshouldcheckifallthevaluesarethesame,and *allowALLinthatcase?Doesn'tseemverypractical,though.
*/ if (!expr->useOr) returnfalse;
/* Only expressions with two arguments are candidates. */ if (list_length(expr->args) != 2) returnfalse;
/* *Weknowit'salways(VarINConst),soweassumethevaristhe *firstargument,andpseudoconstantisthesecondone.
*/ if (!is_pseudo_constant_clause(lsecond(expr->args))) returnfalse;
/* ignore clause by default */
list_attnums[listidx] = InvalidAttrNumber;
if (!bms_is_member(listidx, *estimatedclauses))
{ /* *Ifit'sasimplecolumnreference,justextracttheattnum.If *it'sanexpression,assignanegativeattnumasifitwasa *systemattribute.
*/ if (dependency_is_compatible_clause(clause, rel->relid, &attnum))
{
list_attnums[listidx] = attnum;
} elseif (dependency_is_compatible_expression(clause, rel->relid,
rel->statlist,
&expr))
{ /* special attnum assigned to this expression */
attnum = InvalidAttrNumber;
Assert(expr != NULL);
/* If the expression is duplicate, use the same attnum. */ for (i = 0; i < unique_exprs_cnt; i++)
{ if (equal(unique_exprs[i], expr))
{ /* negative attribute number to expression */
attnum = -(i + 1); break;
}
}
/* not found in the list, so add it */ if (attnum == InvalidAttrNumber)
{
unique_exprs[unique_exprs_cnt++] = expr;
/* after incrementing the value, to get -1, -2, ... */
attnum = (-unique_exprs_cnt);
}
/* remember which attnum was assigned to this clause */
list_attnums[listidx] = attnum;
}
}
/* *Nowthatweknowhowmanyexpressionsthereare,wecanoffsetthe *valuesjustenoughtobuildthebitmapset.
*/ for (i = 0; i < list_length(clauses); i++)
{
AttrNumber attnum;
/* ignore incompatible or already estimated clauses */ if (list_attnums[i] == InvalidAttrNumber) continue;
/* make sure the attnum is in the expected range */
Assert(list_attnums[i] >= (-unique_exprs_cnt));
Assert(list_attnums[i] <= MaxHeapAttributeNumber);
/* make sure the attnum is positive (valid AttrNumber) */
attnum = list_attnums[i] + attnum_offset;
/* Is the expression index is valid? */
Assert((idx >= 0) && (idx < list_length(stat->exprs)));
expr = (Node *) list_nth(stat->exprs, idx);
/* try to find the expression in the unique list */ for (int m = 0; m < unique_exprs_cnt; m++)
{ /* *foundamatchinguniqueexpression,usetheattnum *(derivedfromindexoftheuniqueexpression)
*/ if (equal(unique_exprs[m], expr))
{
unique_attnum = -(m + 1) + attnum_offset; break;
}
}
/* otherwise remap it to the new attnum */
dep->attributes[j] = unique_attnum;
}
/* if found a matching dependency, keep it */ if (!skip)
{ /* maybe we've skipped something earlier, so move it */ if (ndeps != i)
deps->deps[ndeps] = deps->deps[i];
/* if no matching stats could be found then we've nothing to do */ if (nfunc_dependencies == 0)
{
pfree(func_dependencies);
bms_free(clauses_attnums);
pfree(list_attnums);
pfree(unique_exprs); return1.0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.