From 853c47f71a8c8c52236bea5786048b3ff2b96b66 Mon Sep 17 00:00:00 2001
From: Peter Geoghegan <pg@bowt.ie>
Date: Wed, 22 Jan 2020 18:00:38 -0800
Subject: [PATCH v1 1/3] Avoid calling BTreeTupleGetNAtts() in _bt_compare().

---
 src/backend/access/nbtree/nbtsearch.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index c573814f01..96119949a0 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -560,9 +560,9 @@ _bt_compare(Relation rel,
 	BTPageOpaque opaque = (BTPageOpaque) PageGetSpecialPointer(page);
 	IndexTuple	itup;
 	ItemPointer heapTid;
+	int			ski;
 	ScanKey		scankey;
-	int			ncmpkey;
-	int			ntupatts;
+	int			ntupatts = 0;
 
 	Assert(_bt_check_natts(rel, key->heapkeyspace, page, offnum));
 	Assert(key->keysz <= IndexRelationGetNumberOfKeyAttributes(rel));
@@ -576,7 +576,6 @@ _bt_compare(Relation rel,
 		return 1;
 
 	itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offnum));
-	ntupatts = BTreeTupleGetNAtts(itup, rel);
 
 	/*
 	 * The scan key is set up with the attribute number associated with each
@@ -588,12 +587,17 @@ _bt_compare(Relation rel,
 	 * We don't test for violation of this condition here, however.  The
 	 * initial setup for the index scan had better have gotten it right (see
 	 * _bt_first).
+	 *
+	 * We rely on the assumption that every tuple has at least one
+	 * non-truncated attribute from here on.  Delaying our call to
+	 * BTreeTupleGetNAtts() till the end of the first loop iteration has been
+	 * shown to increase throughput on memory-bound workloads.
 	 */
 
-	ncmpkey = Min(ntupatts, key->keysz);
-	Assert(key->heapkeyspace || ncmpkey == key->keysz);
+	Assert(BTreeTupleGetNAtts(itup, rel) >= key->keysz);
+	ski = 1;
 	scankey = key->scankeys;
-	for (int i = 1; i <= ncmpkey; i++)
+	for (;;)
 	{
 		Datum		datum;
 		bool		isNull;
@@ -641,7 +645,13 @@ _bt_compare(Relation rel,
 		if (result != 0)
 			return result;
 
+		ski++;
 		scankey++;
+		if (!ntupatts)
+			ntupatts = BTreeTupleGetNAtts(itup, rel);
+
+		if (ski > key->keysz || ski > ntupatts)
+			break;
 	}
 
 	/*
-- 
2.17.1

