mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-11-21 14:44:00 +00:00
app/vmselect/promql: execute q1
and q2
from q1 op q2
in parallel if labels pushdown cannot be applied
This should improve query performance if VictoriaMetrics has enough resources for processing `q1` and `q2` in parallel. Updates https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2886
This commit is contained in:
parent
69c1272d1b
commit
f992f96a88
2 changed files with 62 additions and 9 deletions
|
@ -399,7 +399,64 @@ func evalBinaryOp(qt *querytracer.Tracer, ec *EvalConfig, be *metricsql.BinaryOp
|
||||||
return rv, nil
|
return rv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func canPushdownCommonFilters(be *metricsql.BinaryOpExpr) bool {
|
||||||
|
switch strings.ToLower(be.Op) {
|
||||||
|
case "or", "default":
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if isAggrFuncWithoutGrouping(be.Left) || isAggrFuncWithoutGrouping(be.Right) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func isAggrFuncWithoutGrouping(e metricsql.Expr) bool {
|
||||||
|
afe, ok := e.(*metricsql.AggrFuncExpr)
|
||||||
|
if !ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return len(afe.Modifier.Args) == 0
|
||||||
|
}
|
||||||
|
|
||||||
func execBinaryOpArgs(qt *querytracer.Tracer, ec *EvalConfig, exprFirst, exprSecond metricsql.Expr, be *metricsql.BinaryOpExpr) ([]*timeseries, []*timeseries, error) {
|
func execBinaryOpArgs(qt *querytracer.Tracer, ec *EvalConfig, exprFirst, exprSecond metricsql.Expr, be *metricsql.BinaryOpExpr) ([]*timeseries, []*timeseries, error) {
|
||||||
|
if !canPushdownCommonFilters(be) {
|
||||||
|
// Execute exprFirst and exprSecond in parallel, since it is impossible to pushdown common filters
|
||||||
|
// from exprFirst to exprSecond.
|
||||||
|
// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2886
|
||||||
|
qt = qt.NewChild("execute left and right sides of %q in parallel", be.Op)
|
||||||
|
defer qt.Done()
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
var tssFirst []*timeseries
|
||||||
|
var errFirst error
|
||||||
|
qtFirst := qt.NewChild("expr1")
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
tssFirst, errFirst = evalExpr(qtFirst, ec, exprFirst)
|
||||||
|
qtFirst.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
var tssSecond []*timeseries
|
||||||
|
var errSecond error
|
||||||
|
qtSecond := qt.NewChild("expr2")
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
tssSecond, errSecond = evalExpr(qtSecond, ec, exprSecond)
|
||||||
|
qtSecond.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
if errFirst != nil {
|
||||||
|
return nil, nil, errFirst
|
||||||
|
}
|
||||||
|
if errSecond != nil {
|
||||||
|
return nil, nil, errFirst
|
||||||
|
}
|
||||||
|
return tssFirst, tssSecond, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Execute binary operation in the following way:
|
// Execute binary operation in the following way:
|
||||||
//
|
//
|
||||||
// 1) execute the exprFirst
|
// 1) execute the exprFirst
|
||||||
|
@ -427,15 +484,9 @@ func execBinaryOpArgs(qt *querytracer.Tracer, ec *EvalConfig, exprFirst, exprSec
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
switch strings.ToLower(be.Op) {
|
lfs := getCommonLabelFilters(tssFirst)
|
||||||
case "or":
|
lfs = metricsql.TrimFiltersByGroupModifier(lfs, be)
|
||||||
// Do not pushdown common label filters from tssFirst for `or` operation, since this can filter out the needed time series from tssSecond.
|
exprSecond = metricsql.PushdownBinaryOpFilters(exprSecond, lfs)
|
||||||
// See https://prometheus.io/docs/prometheus/latest/querying/operators/#logical-set-binary-operators for details.
|
|
||||||
default:
|
|
||||||
lfs := getCommonLabelFilters(tssFirst)
|
|
||||||
lfs = metricsql.TrimFiltersByGroupModifier(lfs, be)
|
|
||||||
exprSecond = metricsql.PushdownBinaryOpFilters(exprSecond, lfs)
|
|
||||||
}
|
|
||||||
tssSecond, err := evalExpr(qt, ec, exprSecond)
|
tssSecond, err := evalExpr(qt, ec, exprSecond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -15,6 +15,8 @@ The following tip changes can be tested by building VictoriaMetrics components f
|
||||||
|
|
||||||
## tip
|
## tip
|
||||||
|
|
||||||
|
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): execute left and right sides of certain operations in parallel. For example, `q1 or q2`, `aggr_func(q1) <op> q2`, `q1 <op> aggr_func(q1)`. This may improve query performance if VictoriaMetrics has enough free resources for parallel processing of both sides of the operation. See [this feature request](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2886).
|
||||||
|
|
||||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): restart all the scrape jobs during [config reload](https://docs.victoriametrics.com/vmagent.html#configuration-update) after `global` section is changed inside `-promscrape.config`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2884).
|
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): restart all the scrape jobs during [config reload](https://docs.victoriametrics.com/vmagent.html#configuration-update) after `global` section is changed inside `-promscrape.config`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2884).
|
||||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly assume role with AWS ECS credentials. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2875). Thanks to @transacid for [the fix](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2876).
|
* BUGFIX: [vmagent](https://docs.victoriametrics.com/vmagent.html): properly assume role with AWS ECS credentials. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/2875). Thanks to @transacid for [the fix](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/2876).
|
||||||
* BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): return series from `q1` if `q2` doesn't return matching time series in the query `q1 ifnot q2`. Previously series from `q1` weren't returned in this case.
|
* BUGFIX: [MetricsQL](https://docs.victoriametrics.com/MetricsQL.html): return series from `q1` if `q2` doesn't return matching time series in the query `q1 ifnot q2`. Previously series from `q1` weren't returned in this case.
|
||||||
|
|
Loading…
Reference in a new issue