app/vmselect/promql: add missing label filters to binary operands before query execution

This implements the optimization described at https://utcc.utoronto.ca/~cks/space/blog/sysadmin/PrometheusLabelNonOptimization

See also https://github.com/cortexproject/cortex/issues/3253
This commit is contained in:
Aliaksandr Valialkin 2020-10-07 21:15:06 +03:00
parent 5ef71974fe
commit e9f2e2cbc9
5 changed files with 88 additions and 4 deletions

View file

@ -175,6 +175,7 @@ func parsePromQLWithCache(q string) (metricsql.Expr, error) {
if pcv == nil {
e, err := metricsql.Parse(q)
if err == nil {
e = metricsql.Optimize(e)
e = adjustCmpOps(e)
}
pcv = &parseCacheValue{

2
go.mod
View file

@ -9,7 +9,7 @@ require (
// like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b
github.com/VictoriaMetrics/fasthttp v1.0.7
github.com/VictoriaMetrics/metrics v1.12.3
github.com/VictoriaMetrics/metricsql v0.6.0
github.com/VictoriaMetrics/metricsql v0.7.0
github.com/aws/aws-sdk-go v1.35.3
github.com/cespare/xxhash/v2 v2.1.1
github.com/golang/snappy v0.0.2

4
go.sum
View file

@ -61,8 +61,8 @@ github.com/VictoriaMetrics/metrics v1.12.2 h1:SG8iAmqavDNuh7GIdHPoGHUhDL23KeKfvS
github.com/VictoriaMetrics/metrics v1.12.2/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE=
github.com/VictoriaMetrics/metrics v1.12.3 h1:Fe6JHC6MSEKa+BtLhPN8WIvS+HKPzMc2evEpNeCGy7I=
github.com/VictoriaMetrics/metrics v1.12.3/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE=
github.com/VictoriaMetrics/metricsql v0.6.0 h1:JnHUmifuA3fdy1GQrmkZJFO+CwFrhLxKwzMv89wNgJ4=
github.com/VictoriaMetrics/metricsql v0.6.0/go.mod h1:ylO7YITho/Iw6P71oEaGyHbO94bGoGtzWfLGqFhMIg8=
github.com/VictoriaMetrics/metricsql v0.7.0 h1:YR/OvbsCH0dwUuc3r5GayTcuTdgWHJZo+4bqbaGl7WM=
github.com/VictoriaMetrics/metricsql v0.7.0/go.mod h1:ylO7YITho/Iw6P71oEaGyHbO94bGoGtzWfLGqFhMIg8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8=
github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM=
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=

View file

@ -0,0 +1,83 @@
package metricsql
import (
"sort"
)
// Optimize optimizes e in order to improve its performance.
func Optimize(e Expr) Expr {
switch t := e.(type) {
case *BinaryOpExpr:
// Convert `foo{filters1} op bar{filters2}` to `foo{filters1, filters2} op bar{filters1, filters2}`.
// This should reduce the number of operations
// See https://utcc.utoronto.ca/~cks/space/blog/sysadmin/PrometheusLabelNonOptimization
// for details.
switch t.Op {
case "+", "-", "*", "/", "%", "^",
"==", "!=", ">", "<", ">=", "<=",
"if", "ifnot", "default":
// The optimization can be applied only to these operations.
default:
return optimizeBinaryOpArgs(t)
}
if t.JoinModifier.Op != "" {
return optimizeBinaryOpArgs(t)
}
if t.GroupModifier.Op != "" {
return optimizeBinaryOpArgs(t)
}
meLeft, ok := t.Left.(*MetricExpr)
if !ok || !meLeft.hasNonEmptyMetricGroup() {
return optimizeBinaryOpArgs(t)
}
meRight, ok := t.Right.(*MetricExpr)
if !ok || !meRight.hasNonEmptyMetricGroup() {
return optimizeBinaryOpArgs(t)
}
lfs := intersectLabelFilters(meLeft.LabelFilters[1:], meRight.LabelFilters[1:])
meLeft.LabelFilters = append(meLeft.LabelFilters[:1], lfs...)
meRight.LabelFilters = append(meRight.LabelFilters[:1], lfs...)
return t
case *FuncExpr:
for i := range t.Args {
t.Args[i] = Optimize(t.Args[i])
}
return t
case *AggrFuncExpr:
for i := range t.Args {
t.Args[i] = Optimize(t.Args[i])
}
return t
default:
return e
}
}
func optimizeBinaryOpArgs(be *BinaryOpExpr) *BinaryOpExpr {
be.Left = Optimize(be.Left)
be.Right = Optimize(be.Right)
return be
}
func intersectLabelFilters(a, b []LabelFilter) []LabelFilter {
m := make(map[string]LabelFilter, len(a)+len(b))
var buf []byte
for _, lf := range a {
buf = lf.AppendString(buf[:0])
m[string(buf)] = lf
}
for _, lf := range b {
buf = lf.AppendString(buf[:0])
m[string(buf)] = lf
}
ss := make([]string, 0, len(m))
for s := range m {
ss = append(ss, s)
}
sort.Strings(ss)
lfs := make([]LabelFilter, 0, len(ss))
for _, s := range ss {
lfs = append(lfs, m[s])
}
return lfs
}

2
vendor/modules.txt vendored
View file

@ -16,7 +16,7 @@ github.com/VictoriaMetrics/fasthttp/fasthttputil
github.com/VictoriaMetrics/fasthttp/stackless
# github.com/VictoriaMetrics/metrics v1.12.3
github.com/VictoriaMetrics/metrics
# github.com/VictoriaMetrics/metricsql v0.6.0
# github.com/VictoriaMetrics/metricsql v0.7.0
github.com/VictoriaMetrics/metricsql
github.com/VictoriaMetrics/metricsql/binaryop
# github.com/aws/aws-sdk-go v1.35.3