diff --git a/app/vmselect/promql/exec.go b/app/vmselect/promql/exec.go index 5f2a798e0..1c731cb5c 100644 --- a/app/vmselect/promql/exec.go +++ b/app/vmselect/promql/exec.go @@ -108,7 +108,7 @@ func maySortResults(e metricsql.Expr) bool { switch v := e.(type) { case *metricsql.FuncExpr: switch strings.ToLower(v.Name) { - case "sort", "sort_desc", + case "sort", "sort_desc", "limit_offset", "sort_by_label", "sort_by_label_desc", "sort_by_label_numeric", "sort_by_label_numeric_desc": // Results already sorted diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go index 54e61b810..8eb398230 100644 --- a/app/vmselect/promql/exec_test.go +++ b/app/vmselect/promql/exec_test.go @@ -9274,6 +9274,75 @@ func TestExecSuccess(t *testing.T) { resultExpected := []netstorage.Result{r1, r2} f(q, resultExpected) }) + t.Run(`limit_offset(5, 0, sort_by_label_numeric_desc(multiple_labels_numbers_special_chars, "foo"))`, func(t *testing.T) { + t.Parallel() + q := `limit_offset(5, 0, sort_by_label_numeric_desc(( + label_set(3, "foo", "1:0:3"), + label_set(4, "foo", "5:0:15"), + label_set(1, "foo", "1:0:2"), + label_set(5, "foo", "7:0:15"), + label_set(7, "foo", "3:0:1"), + label_set(6, "foo", "1:0:2"), + label_set(8, "foo", "9:0:15") + ), "foo"))` + r1 := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{8, 8, 8, 8, 8, 8}, + Timestamps: timestampsExpected, + } + r1.MetricName.Tags = []storage.Tag{ + { + Key: []byte("foo"), + Value: []byte("9:0:15"), + }, + } + r2 := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{5, 5, 5, 5, 5, 5}, + Timestamps: timestampsExpected, + } + r2.MetricName.Tags = []storage.Tag{ + { + Key: []byte("foo"), + Value: []byte("7:0:15"), + }, + } + r3 := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{4, 4, 4, 4, 4, 4}, + Timestamps: timestampsExpected, + } + r3.MetricName.Tags = []storage.Tag{ + { + Key: []byte("foo"), + Value: []byte("5:0:15"), + }, + } + r4 := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{7, 7, 7, 7, 7, 7}, + Timestamps: timestampsExpected, + } + r4.MetricName.Tags = []storage.Tag{ + { + Key: []byte("foo"), + Value: []byte("3:0:1"), + }, + } + r5 := netstorage.Result{ + MetricName: metricNameExpected, + Values: []float64{3, 3, 3, 3, 3, 3}, + Timestamps: timestampsExpected, + } + r5.MetricName.Tags = []storage.Tag{ + { + Key: []byte("foo"), + Value: []byte("1:0:3"), + }, + } + resultExpected := []netstorage.Result{r1, r2, r3, r4, r5} + f(q, resultExpected) + }) t.Run(`sort_by_label_numeric(alias_numbers_with_special_chars)`, func(t *testing.T) { t.Parallel() q := `sort_by_label_numeric(( diff --git a/docs/changelog/CHANGELOG.md b/docs/changelog/CHANGELOG.md index abe3b95b3..59afb5443 100644 --- a/docs/changelog/CHANGELOG.md +++ b/docs/changelog/CHANGELOG.md @@ -19,6 +19,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/). ## tip * BUGFIX: [vmctl](https://docs.victoriametrics.com/vmctl/): drop rows that do not belong to the current series during import. The dropped rows should belong to another series whose tags are a superset of the current series. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7301) and [this pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/7330). Thanks to @dpedu for reporting and cooperating with the test. +* BUGFIX: [vmsingle](https://docs.victoriametrics.com/single-server-victoriametrics/), `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): keep the order of resulting time series when `limit_offset` is applied. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7068). ## [v1.106.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.106.0)