diff --git a/src/box/vinyl.c b/src/box/vinyl.c
index 38c125171e2a52225f3ca9c043d573cd9906de41..606970eb82438607dacbb6402383b4a2da1b6f4d 100644
--- a/src/box/vinyl.c
+++ b/src/box/vinyl.c
@@ -232,7 +232,6 @@ struct vy_stat {
 	int64_t dump_total;
 	/* iterators statistics */
 	struct vy_iterator_stat txw_stat;
-	struct vy_iterator_stat cache_stat;
 };
 
 static struct vy_stat *
@@ -4491,7 +4490,6 @@ vy_info_append_performance(struct vy_env *env, struct info_handler *h)
 
 	info_table_begin(h, "iterator");
 	vy_info_append_iterator_stat(h, "txw", &stat->txw_stat);
-	vy_info_append_iterator_stat(h, "cache", &stat->cache_stat);
 	info_table_end(h);
 
 	info_table_end(h);
@@ -4549,6 +4547,7 @@ vy_index_info(struct vy_index *index, struct info_handler *h)
 {
 	char buf[1024];
 	struct vy_index_stat *stat = &index->stat;
+	struct vy_cache_stat *cache_stat = &index->cache.stat;
 
 	info_begin(h);
 
@@ -4579,6 +4578,15 @@ vy_index_info(struct vy_index *index, struct info_handler *h)
 	vy_info_append_compact_stat(h, "compact", &stat->disk.compact);
 	info_table_end(h);
 
+	info_table_begin(h, "cache");
+	vy_info_append_stmt_counter(h, NULL, &cache_stat->count);
+	info_append_int(h, "lookup", cache_stat->lookup);
+	vy_info_append_stmt_counter(h, "get", &cache_stat->get);
+	vy_info_append_stmt_counter(h, "put", &cache_stat->put);
+	vy_info_append_stmt_counter(h, "invalidate", &cache_stat->invalidate);
+	vy_info_append_stmt_counter(h, "evict", &cache_stat->evict);
+	info_table_end(h);
+
 	info_append_int(h, "range_count", index->range_count);
 	info_append_int(h, "run_count", index->run_count);
 	info_append_int(h, "run_avg", index->run_count / index->range_count);
@@ -7679,8 +7687,7 @@ vy_read_iterator_add_cache(struct vy_read_iterator *itr)
 {
 	struct vy_merge_src *sub_src =
 		vy_merge_iterator_add(&itr->merge_iterator, true, false);
-	struct vy_iterator_stat *stat = &itr->index->env->stat->cache_stat;
-	vy_cache_iterator_open(&sub_src->cache_iterator, stat,
+	vy_cache_iterator_open(&sub_src->cache_iterator,
 			       &itr->index->cache, itr->iterator_type,
 			       itr->key, itr->read_view);
 	if (itr->curr_stmt != NULL) {
diff --git a/src/box/vy_cache.c b/src/box/vy_cache.c
index 33799a89f98aa552e0fb98856b829ecc46cbeec8..7ce43a8efbdb2debd941ccec14a071fc1224aaca 100644
--- a/src/box/vy_cache.c
+++ b/src/box/vy_cache.c
@@ -90,12 +90,14 @@ vy_cache_entry_new(struct vy_cache_env *env, struct vy_cache *cache,
 	rlist_add(&env->cache_lru, &entry->in_lru);
 	env->mem_used += vy_cache_entry_size(entry);
 	env->cached_count++;
+	vy_stmt_counter_acct_tuple(&cache->stat.count, stmt);
 	return entry;
 }
 
 static void
 vy_cache_entry_delete(struct vy_cache_env *env, struct vy_cache_entry *entry)
 {
+	vy_stmt_counter_unacct_tuple(&entry->cache->stat.count, entry->stmt);
 	assert(env->cached_count > 0);
 	env->cached_count--;
 	assert(env->mem_used >= vy_cache_entry_size(entry));
@@ -188,6 +190,7 @@ vy_cache_gc_step(struct vy_cache_env *env)
 		}
 	}
 	cache->version++;
+	vy_stmt_counter_acct_tuple(&cache->stat.evict, entry->stmt);
 	vy_cache_tree_delete(&cache->cache_tree, entry);
 	vy_cache_entry_delete(cache->env, entry);
 }
@@ -294,6 +297,8 @@ vy_cache_add(struct vy_cache *cache, struct tuple *stmt,
 	else if (direction < 0 && boundary_level < entry->right_boundary_level)
 		entry->right_boundary_level = boundary_level;
 
+	vy_stmt_counter_acct_tuple(&cache->stat.put, stmt);
+
 	/* Done if it's not a chain */
 	if (prev_stmt == NULL)
 		return;
@@ -419,6 +424,8 @@ vy_cache_on_write(struct vy_cache *cache, const struct tuple *stmt,
 			*deleted = to_delete->stmt;
 			tuple_ref(to_delete->stmt);
 		}
+		vy_stmt_counter_acct_tuple(&cache->stat.invalidate,
+					   to_delete->stmt);
 		vy_cache_tree_delete(&cache->cache_tree, to_delete);
 		vy_cache_entry_delete(cache->env, to_delete);
 	}
@@ -495,6 +502,14 @@ vy_cache_iterator_is_end_stop(struct vy_cache_iterator *itr,
 	}
 }
 
+static void
+vy_cache_iterator_get(struct vy_cache_iterator *itr, struct tuple **ret)
+{
+	*ret = itr->curr_stmt;
+	if (*ret != NULL)
+		vy_stmt_counter_acct_tuple(&itr->cache->stat.get, *ret);
+}
+
 /**
  * Find next (lower, older) record with the same key as current
  *
@@ -505,7 +520,6 @@ vy_cache_iterator_start(struct vy_cache_iterator *itr, struct tuple **ret,
 {
 	assert(!itr->search_started);
 	assert(itr->curr_stmt == NULL);
-	itr->stat->lookup_count++;
 	*ret = NULL;
 	*stop = false;
 	itr->search_started = true;
@@ -513,6 +527,8 @@ vy_cache_iterator_start(struct vy_cache_iterator *itr, struct tuple **ret,
 	struct vy_cache_tree *tree = &itr->cache->cache_tree;
 	const struct tuple *key = itr->key;
 
+	itr->cache->stat.lookup++;
+
 	if (tuple_field_count(itr->key) > 0) {
 		bool exact;
 		itr->curr_pos = itr->iterator_type == ITER_EQ ||
@@ -558,8 +574,7 @@ vy_cache_iterator_start(struct vy_cache_iterator *itr, struct tuple **ret,
 	}
 	itr->curr_stmt = candidate;
 	tuple_ref(itr->curr_stmt);
-	*ret = itr->curr_stmt;
-	return;
+	vy_cache_iterator_get(itr, ret);
 }
 
 static void
@@ -615,7 +630,6 @@ vy_cache_iterator_next_key(struct vy_stmt_iterator *vitr,
 	}
 	if (!itr->curr_stmt) /* End of search. */
 		return 0;
-	itr->stat->step_count++;
 
 	struct vy_cache_tree *tree = &itr->cache->cache_tree;
 	int dir = iterator_direction(itr->iterator_type);
@@ -677,7 +691,7 @@ vy_cache_iterator_next_key(struct vy_stmt_iterator *vitr,
 		itr->curr_stmt = stmt;
 		tuple_ref(itr->curr_stmt);
 	}
-	*ret = itr->curr_stmt;
+	vy_cache_iterator_get(itr, ret);
 	return 0;
 }
 
@@ -734,11 +748,11 @@ vy_cache_iterator_restore(struct vy_stmt_iterator *vitr,
 				vy_cache_tree_iterator_get_elem(tree, &pos);
 			assert(entry != NULL);
 			vy_cache_iterator_is_stop(itr, *entry, stop);
-			*ret = itr->curr_stmt;
+			vy_cache_iterator_get(itr, ret);
 			return 0;
 		}
 		if (itr->version == itr->cache->version) {
-			*ret = itr->curr_stmt;
+			vy_cache_iterator_get(itr, ret);
 			return 0;
 		}
 		while (true) {
@@ -765,7 +779,7 @@ vy_cache_iterator_restore(struct vy_stmt_iterator *vitr,
 				vy_cache_iterator_is_stop(itr, *entry, stop);
 			}
 		}
-		*ret = itr->curr_stmt;
+		vy_cache_iterator_get(itr, ret);
 		return rc;
 	}
 
@@ -826,13 +840,11 @@ static struct vy_stmt_iterator_iface vy_cache_iterator_iface = {
 };
 
 void
-vy_cache_iterator_open(struct vy_cache_iterator *itr,
-		       struct vy_iterator_stat *stat, struct vy_cache *cache,
+vy_cache_iterator_open(struct vy_cache_iterator *itr, struct vy_cache *cache,
 		       enum iterator_type iterator_type,
 		       const struct tuple *key, const struct vy_read_view **rv)
 {
 	itr->base.iface = &vy_cache_iterator_iface;
-	itr->stat = stat;
 
 	itr->cache = cache;
 	itr->iterator_type = iterator_type;
diff --git a/src/box/vy_cache.h b/src/box/vy_cache.h
index 15f7d39842eab0e2147871a5f96e4b276bd75576..2b2dab5150f649b8e55c7255a6019be7f2b1c47c 100644
--- a/src/box/vy_cache.h
+++ b/src/box/vy_cache.h
@@ -39,6 +39,7 @@
 #include "index.h" /* enum iterator_type */
 #include "vy_stmt.h" /* for comparators */
 #include "vy_stmt_iterator.h" /* struct vy_stmt_iterator */
+#include "vy_stat.h"
 #include "small/mempool.h"
 
 #if defined(__cplusplus)
@@ -153,6 +154,8 @@ struct vy_cache {
 	uint32_t version;
 	/* Saved pointer to common cache environment */
 	struct vy_cache_env *env;
+	/* Cache statistics. */
+	struct vy_cache_stat stat;
 };
 
 /**
@@ -205,8 +208,6 @@ vy_cache_on_write(struct vy_cache *cache, const struct tuple *stmt,
 struct vy_cache_iterator {
 	/** Parent class, must be the first member */
 	struct vy_stmt_iterator base;
-	/** Iterator usage statistics */
-	struct vy_iterator_stat *stat;
 	/* The cache */
 	struct vy_cache *cache;
 
@@ -242,8 +243,7 @@ struct vy_cache_iterator {
  * @param vlsn - LSN visibility, iterator shows values with lsn <= vlsn
  */
 void
-vy_cache_iterator_open(struct vy_cache_iterator *itr,
-		       struct vy_iterator_stat *stat, struct vy_cache *cache,
+vy_cache_iterator_open(struct vy_cache_iterator *itr, struct vy_cache *cache,
 		       enum iterator_type iterator_type,
 		       const struct tuple *key, const struct vy_read_view **rv);
 
diff --git a/src/box/vy_mem.c b/src/box/vy_mem.c
index 215a64749a2659c6b4d767f7f580f4cb8f446666..d80a301c8449d252e6bb140ccc2f8f5290537318 100644
--- a/src/box/vy_mem.c
+++ b/src/box/vy_mem.c
@@ -269,8 +269,7 @@ vy_mem_iterator_copy_to(struct vy_mem_iterator *itr, struct tuple **ret)
 	itr->last_stmt = vy_stmt_dup(itr->curr_stmt, tuple_format(itr->curr_stmt));
 	*ret = itr->last_stmt;
 	if (itr->last_stmt != NULL) {
-		itr->stat->get.rows++;
-		itr->stat->get.bytes += tuple_size(*ret);
+		vy_stmt_counter_acct_tuple(&itr->stat->get, *ret);
 		return 0;
 	}
 	return -1;
diff --git a/src/box/vy_run.c b/src/box/vy_run.c
index 75c20361680d152388174ba47941932dd614f8de..0293f186b300587b6fd355017d872fa2a4ea2085 100644
--- a/src/box/vy_run.c
+++ b/src/box/vy_run.c
@@ -1551,8 +1551,7 @@ vy_run_iterator_get(struct vy_run_iterator *itr, struct tuple **result)
 	if (rc == 0) {
 		itr->curr_stmt_pos = itr->curr_pos;
 		itr->curr_stmt = *result;
-		itr->stat->get.rows++;
-		itr->stat->get.bytes += tuple_size(*result);
+		vy_stmt_counter_acct_tuple(&itr->stat->get, *result);
 	}
 	return rc;
 }
diff --git a/src/box/vy_stat.h b/src/box/vy_stat.h
index 23493ea322f93803954b5c6ef2d1f6496f270888..e62fc267472c972142ac81a0e411a294ec8f6110 100644
--- a/src/box/vy_stat.h
+++ b/src/box/vy_stat.h
@@ -33,6 +33,8 @@
 
 #include <stdint.h>
 
+#include "tuple.h"
+
 #if defined(__cplusplus)
 extern "C" {
 #endif /* defined(__cplusplus) */
@@ -121,6 +123,44 @@ struct vy_index_stat {
 	} disk;
 };
 
+/** Tuple cache statistics. */
+struct vy_cache_stat {
+	/** Number of statements in the cache. */
+	struct vy_stmt_counter count;
+	/** Number of lookups in the cache. */
+	int64_t lookup;
+	/** Number of reads from the cache. */
+	struct vy_stmt_counter get;
+	/** Number of writes to the cache. */
+	struct vy_stmt_counter put;
+	/**
+	 * Number of statements removed from the cache
+	 * due to overwrite.
+	 */
+	struct vy_stmt_counter invalidate;
+	/**
+	 * Number of statements removed from the cache
+	 * due to memory shortage.
+	 */
+	struct vy_stmt_counter evict;
+};
+
+static inline void
+vy_stmt_counter_acct_tuple(struct vy_stmt_counter *c,
+			   const struct tuple *tuple)
+{
+	c->rows++;
+	c->bytes += tuple_size(tuple);
+}
+
+static inline void
+vy_stmt_counter_unacct_tuple(struct vy_stmt_counter *c,
+			     const struct tuple *tuple)
+{
+	c->rows--;
+	c->bytes -= tuple_size(tuple);
+}
+
 static inline void
 vy_stmt_counter_add(struct vy_stmt_counter *c1,
 		    const struct vy_stmt_counter *c2)