From fa33a33654557bb577c6b58fea1f7c9cd7637412 Mon Sep 17 00:00:00 2001
From: ejrh <ejrh00@gmail.com>
Date: Tue, 27 Nov 2018 20:31:58 +1300
Subject: [PATCH 4/4] TID selectivity: reduce the density of the last page by
 half

This takes into account the fact that the last page will have only half the density, on average,
as other pages in a table.
---
 src/backend/utils/adt/selfuncs.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 9bb224d..ccb284b 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -606,8 +606,18 @@ scalarineqsel(PlannerInfo *root, Oid operator, bool isgt, bool iseq,
 			 * assume there will never be any dead tuples or empty space at
 			 * the start or in the middle of the page.  This is likely fine
 			 * for the purposes here.
+			 *
+			 * Since the last page will, on average, be only half full, we can
+			 * estimate it to have half as many tuples as earlier pages.  So
+			 * give it half the weight of a regular page.
 			 */
-			density = vardata->rel->tuples / vardata->rel->pages;
+			density = vardata->rel->tuples / (vardata->rel->pages - 0.5);
+
+			/* If it's the last page, it has half the density. */
+			if (block >= vardata->rel->pages - 1)
+				density *= 0.5;
+
+			/* Add a fraction of a block to take the offset into account. */
 			if (density > 0.0)
 			{
 				OffsetNumber offset = ItemPointerGetOffsetNumberNoCheck(itemptr);
@@ -615,7 +625,11 @@ scalarineqsel(PlannerInfo *root, Oid operator, bool isgt, bool iseq,
 				block += Min(offset / density, 1.0);
 			}
 
-			selec = block / (double) vardata->rel->pages;
+			/*
+			 * Again, the last page has only half weight when converting the
+			 * relative block number to a selectivity.
+			 */
+			selec = block / (vardata->rel->pages - 0.5);
 
 			/*
 			 * We'll have one less tuple for "<" and one additional tuple for
-- 
2.7.4

