diff --git a/lib/mergeset/encoding.go b/lib/mergeset/encoding.go
index f57f4f4e3f..8cb57082cf 100644
--- a/lib/mergeset/encoding.go
+++ b/lib/mergeset/encoding.go
@@ -540,6 +540,17 @@ func putLensBuffer(lb *lensBuffer) {
 	lensBufferPool.Put(lb)
 }
 
-func newInmemoryBlock() *inmemoryBlock {
-	return &inmemoryBlock{}
+func getInmemoryBlock() *inmemoryBlock {
+	v := ibPool.Get()
+	if v == nil {
+		return &inmemoryBlock{}
+	}
+	return v.(*inmemoryBlock)
 }
+
+func putInmemoryBlock(ib *inmemoryBlock) {
+	ib.Reset()
+	ibPool.Put(ib)
+}
+
+var ibPool sync.Pool
diff --git a/lib/mergeset/part_search.go b/lib/mergeset/part_search.go
index d2a8a1116c..8671561b63 100644
--- a/lib/mergeset/part_search.go
+++ b/lib/mergeset/part_search.go
@@ -316,7 +316,7 @@ func (ps *partSearch) readInmemoryBlock(bh *blockHeader) (*inmemoryBlock, error)
 	ps.sb.lensData = bytesutil.Resize(ps.sb.lensData, int(bh.lensBlockSize))
 	ps.p.lensFile.MustReadAt(ps.sb.lensData, int64(bh.lensBlockOffset))
 
-	ib := newInmemoryBlock()
+	ib := getInmemoryBlock()
 	if err := ib.UnmarshalData(&ps.sb, bh.firstItem, bh.commonPrefix, bh.itemsCount, bh.marshalType); err != nil {
 		return nil, fmt.Errorf("cannot unmarshal storage block with %d items: %w", bh.itemsCount, err)
 	}
diff --git a/lib/mergeset/table.go b/lib/mergeset/table.go
index 6a9eb7bed1..ba12ada94c 100644
--- a/lib/mergeset/table.go
+++ b/lib/mergeset/table.go
@@ -182,15 +182,16 @@ func (ris *rawItemsShard) addItems(tb *Table, items [][]byte) error {
 	ris.mu.Lock()
 	ibs := ris.ibs
 	if len(ibs) == 0 {
-		ib := newInmemoryBlock()
+		ib := getInmemoryBlock()
 		ibs = append(ibs, ib)
 		ris.ibs = ibs
 	}
 	ib := ibs[len(ibs)-1]
 	for _, item := range items {
 		if !ib.Add(item) {
-			ib = newInmemoryBlock()
+			ib = getInmemoryBlock()
 			if !ib.Add(item) {
+				putInmemoryBlock(ib)
 				err = fmt.Errorf("cannot insert an item %q into an empty inmemoryBlock; it looks like the item is too large? len(item)=%d", item, len(item))
 				break
 			}
@@ -674,13 +675,13 @@ func (tb *Table) mergeRawItemsBlocks(blocksToMerge []*inmemoryBlock) {
 func (tb *Table) mergeInmemoryBlocks(blocksToMerge []*inmemoryBlock) *partWrapper {
 	// Convert blocksToMerge into inmemoryPart's
 	mps := make([]*inmemoryPart, 0, len(blocksToMerge))
-	for i, ib := range blocksToMerge {
+	for _, ib := range blocksToMerge {
 		if len(ib.items) == 0 {
 			continue
 		}
 		mp := getInmemoryPart()
 		mp.Init(ib)
-		blocksToMerge[i] = nil
+		putInmemoryBlock(ib)
 		mps = append(mps, mp)
 	}
 	if len(mps) == 0 {