diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 4a3b3094a0..8274704af7 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -859,6 +859,7 @@ InitCatCache(int id,
 	for (i = 0; i < nkeys; ++i)
 		cp->cc_keyno[i] = key[i];
 	cp->cc_tupsize = 0;
+	cp->cc_noprune_until = 0;
 
 	/*
 	 * new cache is initialized as far as we can go for now. print some
@@ -898,6 +899,7 @@ CatCacheCleanupOldEntries(CatCache *cp)
 	int			i;
 	int			nremoved = 0;
 	size_t		hash_size;
+	TimestampTz oldest_lastaccess = 0;
 #ifdef CATCACHE_STATS
 	/* These variables are only for debugging purpose */
 	int			ntotal = 0;
@@ -918,6 +920,10 @@ CatCacheCleanupOldEntries(CatCache *cp)
 	if (cache_prune_min_age < 0)
 		return false;
 
+	/* Return immediately if apparently no entry to remove */
+	if (cp->cc_noprune_until == 0 || catcacheclock <= cp->cc_noprune_until)
+		return false;
+
 	/*
 	 * Return without pruning if the size of the hash is below the target.
 	 */
@@ -939,6 +945,7 @@ CatCacheCleanupOldEntries(CatCache *cp)
 			CatCTup    *ct = dlist_container(CatCTup, cache_elem, iter.cur);
 			long entry_age;
 			int us;
+			bool removed = false;
 
 
 			/*
@@ -982,12 +989,24 @@ CatCacheCleanupOldEntries(CatCache *cp)
 					{
 						CatCacheRemoveCTup(cp, ct);
 						nremoved++;
+						removed = true;
 					}
 				}
 			}
+
+			/* Take the oldest lastaccess among survived entries */
+			if (!removed &&
+				(oldest_lastaccess == 0 || ct->lastaccess < oldest_lastaccess))
+				oldest_lastaccess = ct->lastaccess;
 		}
 	}
 
+	/* Calculate the next pruning time if any entry remains */
+	if (oldest_lastaccess > 0)
+		oldest_lastaccess += cache_prune_min_age * USECS_PER_SEC;
+
+	cp->cc_noprune_until = oldest_lastaccess;
+
 #ifdef CATCACHE_STATS
 	StaticAssertStmt(SYSCACHE_STATS_NAGECLASSES == 6,
 					 "number of syscache age class must be 6");
@@ -1423,6 +1442,11 @@ SearchCatCacheInternal(CatCache *cache,
 			ct->naccess++;
 		ct->lastaccess = catcacheclock;
 
+		/* the first entry determines the next pruning time */
+		if (cache_prune_min_age >= 0 && cache->cc_noprune_until == 0)
+			cache->cc_noprune_until =
+				ct->lastaccess + cache_prune_min_age * USECS_PER_SEC;
+
 		/*
 		 * If it's a positive entry, bump its refcount and return it. If it's
 		 * negative, we can report failure to the caller.
diff --git a/src/include/utils/catcache.h b/src/include/utils/catcache.h
index 4d51975920..1750919399 100644
--- a/src/include/utils/catcache.h
+++ b/src/include/utils/catcache.h
@@ -63,7 +63,8 @@ typedef struct catcache
 	ScanKeyData cc_skey[CATCACHE_MAXKEYS];	/* precomputed key info for heap
 											 * scans */
 	int			cc_tupsize;		/* total amount of catcache tuples */
-
+	TimestampTz	cc_noprune_until; /* Skip pruning until this time has passed
+								   * zero means no entry lives in this cache */
 	/*
 	 * Statistics entries
 	 */
