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