diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index d597b7e81f..c7a731c69f 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -6145,6 +6145,8 @@ get_actual_variable_endpoint(Relation heapRel,
 	Datum		values[INDEX_MAX_KEYS];
 	bool		isnull[INDEX_MAX_KEYS];
 	MemoryContext oldcontext;
+	double		endpoint_cost = 0.0;
+	BlockNumber	last_block = InvalidBlockNumber;
 
 	/*
 	 * We use the index-only-scan machinery for this.  With mostly-static
@@ -6197,13 +6199,26 @@ get_actual_variable_endpoint(Relation heapRel,
 	/* Fetch first/next tuple in specified direction */
 	while ((tid = index_getnext_tid(index_scan, indexscandir)) != NULL)
 	{
+		BlockNumber block = ItemPointerGetBlockNumber(tid);
 		if (!VM_ALL_VISIBLE(heapRel,
-							ItemPointerGetBlockNumber(tid),
+							block,
 							&vmbuffer))
 		{
 			/* Rats, we have to visit the heap to check visibility */
 			if (!index_fetch_heap(index_scan, tableslot))
-				continue;		/* no visible tuple, try next index entry */
+			{
+				CHECK_FOR_INTERRUPTS();
+				if (block != last_block)
+					endpoint_cost += random_page_cost;
+				else
+					endpoint_cost += cpu_tuple_cost;
+				last_block = block;
+#define ENDPOINT_COST_LIMIT 20.0
+				if (endpoint_cost > ENDPOINT_COST_LIMIT)
+					break;
+				else
+					continue;		/* no visible tuple, try next index entry */
+			}
 
 			/* We don't actually need the heap tuple for anything */
 			ExecClearTuple(tableslot);
