diff --git a/tsdb/engine/tsm1/encoding.gen.go b/tsdb/engine/tsm1/encoding.gen.go
index eb993a8395..0dc479cb2d 100644
--- a/tsdb/engine/tsm1/encoding.gen.go
+++ b/tsdb/engine/tsm1/encoding.gen.go
@@ -56,18 +56,20 @@ func (a Values) assertOrdered() {
 // Deduplicate returns a new slice with any values that have the same timestamp removed.
 // The Value that appears last in the slice is the one that is kept.
 func (a Values) Deduplicate() Values {
-	m := make(map[int64]Value)
-	for _, val := range a {
-		m[val.UnixNano()] = val
+	if len(a) == 0 {
+		return a
 	}
+	sort.Stable(a)
+	var i int
+	for j := 1; j < len(a); j++ {
+		v := a[j]
+		if v.UnixNano() != a[i].UnixNano() {
+			i++
+		}
+		a[i] = v
 
-	other := make(Values, 0, len(m))
-	for _, val := range m {
-		other = append(other, val)
 	}
-
-	sort.Sort(other)
-	return other
+	return a[:i+1]
 }
 
 //  Exclude returns the subset of values not in [min, max]
@@ -227,18 +229,20 @@ func (a FloatValues) assertOrdered() {
 // Deduplicate returns a new slice with any values that have the same timestamp removed.
 // The Value that appears last in the slice is the one that is kept.
 func (a FloatValues) Deduplicate() FloatValues {
-	m := make(map[int64]FloatValue)
-	for _, val := range a {
-		m[val.UnixNano()] = val
+	if len(a) == 0 {
+		return a
 	}
+	sort.Stable(a)
+	var i int
+	for j := 1; j < len(a); j++ {
+		v := a[j]
+		if v.UnixNano() != a[i].UnixNano() {
+			i++
+		}
+		a[i] = v
 
-	other := make(FloatValues, 0, len(m))
-	for _, val := range m {
-		other = append(other, val)
 	}
-
-	sort.Sort(other)
-	return other
+	return a[:i+1]
 }
 
 //  Exclude returns the subset of values not in [min, max]
@@ -398,18 +402,20 @@ func (a IntegerValues) assertOrdered() {
 // Deduplicate returns a new slice with any values that have the same timestamp removed.
 // The Value that appears last in the slice is the one that is kept.
 func (a IntegerValues) Deduplicate() IntegerValues {
-	m := make(map[int64]IntegerValue)
-	for _, val := range a {
-		m[val.UnixNano()] = val
+	if len(a) == 0 {
+		return a
 	}
+	sort.Stable(a)
+	var i int
+	for j := 1; j < len(a); j++ {
+		v := a[j]
+		if v.UnixNano() != a[i].UnixNano() {
+			i++
+		}
+		a[i] = v
 
-	other := make(IntegerValues, 0, len(m))
-	for _, val := range m {
-		other = append(other, val)
 	}
-
-	sort.Sort(other)
-	return other
+	return a[:i+1]
 }
 
 //  Exclude returns the subset of values not in [min, max]
@@ -569,18 +575,20 @@ func (a StringValues) assertOrdered() {
 // Deduplicate returns a new slice with any values that have the same timestamp removed.
 // The Value that appears last in the slice is the one that is kept.
 func (a StringValues) Deduplicate() StringValues {
-	m := make(map[int64]StringValue)
-	for _, val := range a {
-		m[val.UnixNano()] = val
+	if len(a) == 0 {
+		return a
 	}
+	sort.Stable(a)
+	var i int
+	for j := 1; j < len(a); j++ {
+		v := a[j]
+		if v.UnixNano() != a[i].UnixNano() {
+			i++
+		}
+		a[i] = v
 
-	other := make(StringValues, 0, len(m))
-	for _, val := range m {
-		other = append(other, val)
 	}
-
-	sort.Sort(other)
-	return other
+	return a[:i+1]
 }
 
 //  Exclude returns the subset of values not in [min, max]
@@ -740,18 +748,20 @@ func (a BooleanValues) assertOrdered() {
 // Deduplicate returns a new slice with any values that have the same timestamp removed.
 // The Value that appears last in the slice is the one that is kept.
 func (a BooleanValues) Deduplicate() BooleanValues {
-	m := make(map[int64]BooleanValue)
-	for _, val := range a {
-		m[val.UnixNano()] = val
+	if len(a) == 0 {
+		return a
 	}
+	sort.Stable(a)
+	var i int
+	for j := 1; j < len(a); j++ {
+		v := a[j]
+		if v.UnixNano() != a[i].UnixNano() {
+			i++
+		}
+		a[i] = v
 
-	other := make(BooleanValues, 0, len(m))
-	for _, val := range m {
-		other = append(other, val)
 	}
-
-	sort.Sort(other)
-	return other
+	return a[:i+1]
 }
 
 //  Exclude returns the subset of values not in [min, max]
diff --git a/tsdb/engine/tsm1/encoding.gen.go.tmpl b/tsdb/engine/tsm1/encoding.gen.go.tmpl
index 58355e5909..f61caf9354 100644
--- a/tsdb/engine/tsm1/encoding.gen.go.tmpl
+++ b/tsdb/engine/tsm1/encoding.gen.go.tmpl
@@ -53,18 +53,20 @@ func (a {{.Name}}Values) assertOrdered() {
 // Deduplicate returns a new slice with any values that have the same timestamp removed.
 // The Value that appears last in the slice is the one that is kept.
 func (a {{.Name}}Values) Deduplicate() {{.Name}}Values {
-	m := make(map[int64]{{.Name}}Value)
-	for _, val := range a {
-		m[val.UnixNano()] = val
+	if len(a) == 0 {
+		return a
 	}
+	sort.Stable(a)
+	var i int
+	for j := 1; j < len(a); j++ {
+		v := a[j]
+		if v.UnixNano() != a[i].UnixNano() {
+			i++
+		}
+		a[i] = v
 
-	other := make({{.Name}}Values, 0, len(m))
-	for _, val := range m {
-		other = append(other, val)
 	}
-
-	sort.Sort(other)
-	return other
+	return a[:i+1]
 }
 
 //  Exclude returns the subset of values not in [min, max]
diff --git a/tsdb/engine/tsm1/encoding_test.go b/tsdb/engine/tsm1/encoding_test.go
index 07e36b124c..9391a4ec67 100644
--- a/tsdb/engine/tsm1/encoding_test.go
+++ b/tsdb/engine/tsm1/encoding_test.go
@@ -493,10 +493,16 @@ func TestValues_MergeFloat(t *testing.T) {
 			t.Fatalf("test(%d): value length mismatch: exp %v, got %v", i, exp, got)
 		}
 
+		dedup := tsm1.Values(append(test.a, test.b...)).Deduplicate()
+
 		for i := range test.exp {
 			if exp, got := test.exp[i].String(), got[i].String(); exp != got {
 				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
 			}
+
+			if exp, got := test.exp[i].String(), dedup[i].String(); exp != got {
+				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
+			}
 		}
 	}
 }
@@ -626,10 +632,16 @@ func TestIntegerValues_Merge(t *testing.T) {
 			t.Fatalf("test(%d): value length mismatch: exp %v, got %v", i, exp, got)
 		}
 
+		dedup := tsm1.IntegerValues(append(test.a, test.b...)).Deduplicate()
+
 		for i := range test.exp {
 			if exp, got := test.exp[i].String(), got[i].String(); exp != got {
 				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
 			}
+
+			if exp, got := test.exp[i].String(), dedup[i].String(); exp != got {
+				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
+			}
 		}
 	}
 }
@@ -755,10 +767,16 @@ func TestFloatValues_Merge(t *testing.T) {
 			t.Fatalf("test(%d): value length mismatch: exp %v, got %v", i, exp, got)
 		}
 
+		dedup := tsm1.FloatValues(append(test.a, test.b...)).Deduplicate()
+
 		for i := range test.exp {
 			if exp, got := test.exp[i].String(), got[i].String(); exp != got {
 				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
 			}
+
+			if exp, got := test.exp[i].String(), dedup[i].String(); exp != got {
+				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
+			}
 		}
 	}
 }
@@ -884,10 +902,16 @@ func TestBooleanValues_Merge(t *testing.T) {
 			t.Fatalf("test(%d): value length mismatch: exp %v, got %v", i, exp, got)
 		}
 
+		dedup := tsm1.BooleanValues(append(test.a, test.b...)).Deduplicate()
+
 		for i := range test.exp {
 			if exp, got := test.exp[i].String(), got[i].String(); exp != got {
 				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
 			}
+
+			if exp, got := test.exp[i].String(), dedup[i].String(); exp != got {
+				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
+			}
 		}
 	}
 }
@@ -1017,10 +1041,16 @@ func TestStringValues_Merge(t *testing.T) {
 			t.Fatalf("test(%d): value length mismatch: exp %v, got %v", i, exp, got)
 		}
 
+		dedup := tsm1.StringValues(append(test.a, test.b...)).Deduplicate()
+
 		for i := range test.exp {
 			if exp, got := test.exp[i].String(), got[i].String(); exp != got {
 				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
 			}
+
+			if exp, got := test.exp[i].String(), dedup[i].String(); exp != got {
+				t.Fatalf("value mismatch:\n exp %v\n got %v", exp, got)
+			}
 		}
 	}
 }