diff --git a/app/vmselect/netstorage/netstorage.go b/app/vmselect/netstorage/netstorage.go
index e00ed4d4e5..34dc4c4956 100644
--- a/app/vmselect/netstorage/netstorage.go
+++ b/app/vmselect/netstorage/netstorage.go
@@ -1180,10 +1180,14 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin
 	var buf []byte
 
 	// metricNamesBuf is used for holding all the loaded unique metric names.
-	// It should reduce pressure on Go garbage collector by reducing
-	// the number of memory allocations when constructing metricName string from byte slice.
+	// It should reduce pressure on Go GC by reducing the number of string allocations
+	// when constructing metricName string from byte slice.
 	var metricNamesBuf []byte
 
+	// brssBuf is used for holding all the blockRefs objects across all the loaded time series.
+	// It should reduce pressure on Go GC by reducing the number of blockRefs allocations.
+	var brssBuf []blockRefs
+
 	for sr.NextMetricBlock() {
 		blocksRead++
 		if deadline.Exceeded() {
@@ -1208,7 +1212,12 @@ func ProcessSearchQuery(qt *querytracer.Tracer, sq *storage.SearchQuery, deadlin
 		metricName := sr.MetricBlockRef.MetricName
 		brs := m[string(metricName)]
 		if brs == nil {
-			brs = &blockRefs{}
+			if cap(brssBuf) > len(brssBuf) {
+				brssBuf = brssBuf[:len(brssBuf)+1]
+			} else {
+				brssBuf = append(brssBuf, blockRefs{})
+			}
+			brs = &brssBuf[len(brssBuf)-1]
 			brs.brs = brs.brsPrealloc[:0]
 		}
 		brs.brs = append(brs.brs, blockRef{