From ae3e1bd313475a4bf3933870939cdb43de7bdf50 Mon Sep 17 00:00:00 2001 From: Edmund Horner Date: Fri, 12 Oct 2018 13:36:24 +1300 Subject: [PATCH 1/4] Add selectivity and nullness estimates for CTID system variables Previously, estimates for ItemPointer range quals, such as "ctid <= '(5,7)'", resorted to the default values of 0.33 for range selectivity, and 0.005 for nullness, although there was special-case handling for equality quals like "ctid = (5,7)", which used the appropriate selectivity for distinct items. This change uses the relation size to estimate the selectivity of a range qual, and also uses a nullness estimate of 0 for ctid, since it is never NULL. --- src/backend/utils/adt/selfuncs.c | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index e0ece74..f430a2b 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -571,6 +571,49 @@ scalarineqsel(PlannerInfo *root, Oid operator, bool isgt, bool iseq, if (!HeapTupleIsValid(vardata->statsTuple)) { + /* + * There are no stats for system columns, but for CTID we can estimate + * based on table size. + */ + if (vardata->var && IsA(vardata->var, Var) && + ((Var *) vardata->var)->varattno == SelfItemPointerAttributeNumber) + { + ItemPointer itemptr; + double block; + double density; + + /* If the relation's empty, we're going to include all of it. */ + if (vardata->rel->pages == 0) + return 1.0; + + itemptr = (ItemPointer) DatumGetPointer(constval); + block = ItemPointerGetBlockNumberNoCheck(itemptr); + + /* + * If there's a useable density (tuples per page) estimate, take + * into account the fraction of a block with a lower TID offset. + */ + density = vardata->rel->tuples / vardata->rel->pages; + if (density > 0.0) + { + OffsetNumber offset = ItemPointerGetOffsetNumberNoCheck(itemptr); + + block += Min(offset / density, 1.0); + } + + selec = block / (double) vardata->rel->pages; + + /* For <= and >=, one extra item is included. */ + if (iseq && vardata->rel->tuples >= 1.0) + selec += (1 / vardata->rel->tuples); + + if (isgt) + selec = 1.0 - selec; + + CLAMP_PROBABILITY(selec); + return selec; + } + /* no stats available, so default result */ return DEFAULT_INEQ_SEL; } @@ -1785,6 +1828,15 @@ nulltestsel(PlannerInfo *root, NullTestType nulltesttype, Node *arg, return (Selectivity) 0; /* keep compiler quiet */ } } + else if (vardata.var && IsA(vardata.var, Var) && + ((Var *) vardata.var)->varattno == SelfItemPointerAttributeNumber) + { + /* + * There are no stats for system columns, but we know CTID is never + * NULL. + */ + selec = (nulltesttype == IS_NULL) ? 0.0 : 1.0; + } else { /* -- 2.7.4