diff --git i/src/backend/optimizer/plan/planner.c w/src/backend/optimizer/plan/planner.c
index 5d515842dc..65d74be557 100644
--- i/src/backend/optimizer/plan/planner.c
+++ w/src/backend/optimizer/plan/planner.c
@@ -316,6 +316,10 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
 	glob->transientPlan = false;
 	glob->dependsOnRole = false;
 
+
+	/* clear crappy variable range cache */
+	clear_variable_range_cache();
+
 	/*
 	 * Assess whether it's feasible to use parallel mode for this query. We
 	 * can't do this in a standalone backend, or if the command will try to
diff --git i/src/backend/utils/adt/selfuncs.c w/src/backend/utils/adt/selfuncs.c
index e96bfce4dc..0e0cc68307 100644
--- i/src/backend/utils/adt/selfuncs.c
+++ w/src/backend/utils/adt/selfuncs.c
@@ -5567,6 +5567,99 @@ get_stats_slot_range(AttStatsSlot *sslot, Oid opfuncoid, FmgrInfo *opproc,
 }
 
 
+/*
+ * a lot of crappy code to emulate variable range caching
+ * just intended for testing purposes
+ */
+typedef struct ActualVariableRangeCache ActualVariableRangeCache;
+struct ActualVariableRangeCache {
+	Oid		indexoid;
+	int64	min_value;
+	int64	max_value;
+	bool	has_min;
+	bool	has_max;
+};
+
+static unsigned long range_caches_size = 0;
+static ActualVariableRangeCache range_caches[1000] = {{0, 0, 0, false, false}};
+
+void
+clear_variable_range_cache(void)
+{
+	for (unsigned long i = 0; i < range_caches_size; i++) {
+		range_caches[i].indexoid = 0;
+		range_caches[i].has_min = false;
+		range_caches[i].has_max = false;
+	}
+	range_caches_size = 0;
+}
+
+static bool
+get_cached_actual_variable_min(Oid indexoid, Datum *min)
+{
+	for (unsigned long i = 0; i < range_caches_size; i++) {
+		if (range_caches[i].indexoid == indexoid) {
+			if (!range_caches[i].has_min)
+				return false;
+
+			*min = range_caches[i].min_value;
+			return true;
+		}
+	}
+	return false;
+}
+
+
+static bool
+get_cached_actual_variable_max(Oid indexoid, Datum *max)
+{
+	for (unsigned long i = 0; i < range_caches_size; i++) {
+		if (range_caches[i].indexoid == indexoid) {
+			if (!range_caches[i].has_max)
+				return false;
+
+			*max = range_caches[i].max_value;
+			return true;
+		}
+	}
+	return false;
+}
+
+
+static void
+add_actual_variable_min_to_cache(Oid indexoid, Datum *min)
+{
+	for (unsigned long i = 0; i < range_caches_size; i++) {
+		if (range_caches[i].indexoid == indexoid) {
+			range_caches[i].min_value = *min;
+			range_caches[i].has_min = true;
+			return;
+		}
+	}
+	range_caches[range_caches_size].indexoid = indexoid;
+	range_caches[range_caches_size].min_value = *min;
+	range_caches[range_caches_size].has_min = true;
+	range_caches_size++;
+}
+
+
+static void
+add_actual_variable_max_to_cache(Oid indexoid, Datum *max)
+{
+	for (unsigned long i = 0; i < range_caches_size; i++) {
+		if (range_caches[i].indexoid == indexoid) {
+			range_caches[i].max_value = *max;
+			range_caches[i].has_max = true;
+			return;
+		}
+	}
+	range_caches[range_caches_size].indexoid = indexoid;
+	range_caches[range_caches_size].max_value = *max;
+	range_caches[range_caches_size].has_max = true;
+	range_caches_size++;
+}
+
+
 /*
  * get_actual_variable_range
  *		Attempt to identify the current *actual* minimum and/or maximum
@@ -5691,15 +5784,23 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
 			/* If min is requested ... */
 			if (min)
 			{
-				have_data = get_actual_variable_endpoint(heapRel,
-														 indexRel,
-														 indexscandir,
-														 scankeys,
-														 typLen,
-														 typByVal,
-														 slot,
-														 oldcontext,
-														 min);
+				/* try to reuse min from previous planner nodes */
+				have_data = get_cached_actual_variable_min(index->indexoid, min);
+				/* or fetch from index if first time here */
+				if (!have_data)
+					have_data = get_actual_variable_endpoint(heapRel,
+															 indexRel,
+															 indexscandir,
+															 scankeys,
+															 typLen,
+															 typByVal,
+															 slot,
+															 oldcontext,
+															 min);
+				/* update the min memorization */
+				if (have_data)
+					add_actual_variable_min_to_cache(index->indexoid,
+													 min);
 			}
 			else
 			{
@@ -5710,16 +5811,25 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata,
 			/* If max is requested, and we didn't find the index is empty */
 			if (max && have_data)
 			{
+				/* try to reuse max from previous planner nodes */
+				have_data = get_cached_actual_variable_max(index->indexoid, max);
+
+				/* or fetch from index if first time here */
 				/* scan in the opposite direction; all else is the same */
-				have_data = get_actual_variable_endpoint(heapRel,
-														 indexRel,
-														 -indexscandir,
-														 scankeys,
-														 typLen,
-														 typByVal,
-														 slot,
-														 oldcontext,
-														 max);
+				if (!have_data)
+					have_data = get_actual_variable_endpoint(heapRel,
+															 indexRel,
+															 -indexscandir,
+															 scankeys,
+															 typLen,
+															 typByVal,
+															 slot,
+															 oldcontext,
+															 max);
+				/* update the max memorization */
+				if (have_data)
+					add_actual_variable_max_to_cache(index->indexoid,
+													 max);
 			}
 
 			/* Clean everything up */
diff --git i/src/include/utils/selfuncs.h w/src/include/utils/selfuncs.h
index 7ac4a06391..a46c272ac7 100644
--- i/src/include/utils/selfuncs.h
+++ w/src/include/utils/selfuncs.h
@@ -220,4 +220,7 @@ extern Selectivity scalararraysel_containment(PlannerInfo *root,
 											  Oid elemtype, bool isEquality, bool useOr,
 											  int varRelid);
 
+extern void
+clear_variable_range_cache(void);
+
 #endif							/* SELFUNCS_H */
