diff --git a/tsdb/shard.go b/tsdb/shard.go
index <HASH>..<HASH> 100644
--- a/tsdb/shard.go
+++ b/tsdb/shard.go
@@ -914,17 +914,28 @@ func (s *Shard) monitor() {
 	defer t.Stop()
 	t2 := time.NewTicker(time.Minute)
 	defer t2.Stop()
+	var changed time.Time
+
 	for {
 		select {
 		case <-s.closing:
 			return
 		case <-t.C:
+
+			// Checking DiskSize can be expensive with a lot of shards and TSM files, only
+			// check if something has changed.
+			lm := s.LastModified()
+			if lm.Equal(changed) {
+				continue
+			}
+
 			size, err := s.DiskSize()
 			if err != nil {
 				s.logger.Info(fmt.Sprintf("Error collecting shard size: %v", err))
 				continue
 			}
 			atomic.StoreInt64(&s.stats.DiskBytes, size)
+			changed = lm
 		case <-t2.C:
 			if s.options.Config.MaxValuesPerTag == 0 {
 				continue
Only calculate disk size if shard has changed

Calling DiskSize can be expensive with many shards.  Since the stats
collection runs this every <I>s by default, it can be expensive and
wasteful to calculate the stats when nothing has changed. This avoids
re-calculating the shard size unless something has chagned.