mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-10-06 03:52:28 +00:00
* perf(promql): reuse sliding min and max candidates Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com> * test(promql): simplify extrema benchmark parameters Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com> * test(promql): record baseline sliding extrema SQL results Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com> * perf(promql): rescan windows that barely overlap Reusing candidates loses to a plain scan when consecutive windows overlap little: the deque bookkeeping then costs more than the rescan it replaces. A local Criterion run on 4096 samples at width 240 / step 240 measured 10.79 -> 22.14 us for min and 12.83 -> 19.85 us for max. Pick the evaluator once per batch from the first two windows. RangeManipulate emits one window length and one step per batch, so that sample decides for all of them, and both evaluators return identical bits, so a wrong pick costs time only. Batches that do not qualify fold each window on its own. Move the incremental state into SlidingExtrema so tests can drive it directly: the exhaustive four-sample differential test cannot reach it through a UDF call, because such a batch never qualifies for reuse. Signed-off-by: Dennis Zhuang <xzhuang@greptime.com> * fix(promql): select the extrema evaluator from batch averages Reading the window shape off the first two windows misreads the batch. RangeManipulate starts a series at max(query start, first aligned sample), so a series that begins inside the query range gets a first window covering roughly one step, and a window covering no sample at all is emitted as (0, 0). Either one closed the gate for the whole batch, including the one-hour window at a 15s step that candidate reuse was written for. Compare the batch averages instead: at least 32 samples per window, and a step advancing at most a quarter of that. Uniform batches select exactly as before, so the thresholds keep the meaning they were measured with. The 32-sample rule had also moved most of the benchmark and query-regression shapes onto the rescan, including the case built to measure reset and rebuild. Widen those windows to 40 samples, add a step at the selection boundary, and add an end-to-end case with 40-sample windows advancing 5. Signed-off-by: Dennis Zhuang <xzhuang@greptime.com> * fix(promql): ignore empty windows when measuring batch advance The advance was read from the first and last window offsets, but a window covering no sample is emitted as (0, 0). A query whose last evaluation lands exactly one window past the last sample ends on such a window, and its zero offset made a batch of disjoint windows look like one that never moved, which selected the evaluator built for overlap. Results stayed correct; the cost was deque bookkeeping on the shape the scan fallback exists for. Take the offset span over the windows that cover a sample. Empty windows stay in the window count, where they only make both conditions stricter. Signed-off-by: Dennis Zhuang <xzhuang@greptime.com> --------- Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com> Signed-off-by: Dennis Zhuang <xzhuang@greptime.com> Co-authored-by: Dennis Zhuang <xzhuang@greptime.com>
249 lines
8.1 KiB
SQL
249 lines
8.1 KiB
SQL
-- Port from Prometheus `promql/promqltest/testdata/functions.test`.
|
|
-- Include stddev/stdvar over time
|
|
|
|
-- load 10s
|
|
-- metric 0 8 8 2 3
|
|
create table metric (ts timestamp(3) time index, val double);
|
|
|
|
insert into metric values
|
|
(0,0),
|
|
(10000,8),
|
|
(20000,8),
|
|
(30000,2),
|
|
(40000,3);
|
|
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
select * from metric;
|
|
|
|
-- eval instant at 1m stdvar_over_time(metric[2m])
|
|
-- {} 10.56
|
|
tql eval (60, 60, '1s') stdvar_over_time(metric[2m]);
|
|
|
|
-- eval instant at 1m stddev_over_time(metric[2m])
|
|
-- {} 3.249615
|
|
tql eval (60, 60, '1s') stddev_over_time(metric[2m]);
|
|
|
|
-- eval instant at 1m stddev_over_time((metric[2m]))
|
|
-- {} 3.249615
|
|
tql eval (60, 60, '1s') stddev_over_time((metric[2m]));
|
|
|
|
drop table metric;
|
|
|
|
-- load 10s
|
|
-- metric 1.5990505637277868 1.5990505637277868 1.5990505637277868
|
|
create table metric (ts timestamp(3) time index, val double);
|
|
|
|
insert into metric values
|
|
(0,1.5990505637277868),
|
|
(10000,1.5990505637277868),
|
|
(20000,1.5990505637277868);
|
|
|
|
-- eval instant at 55s stdvar_over_time(metric[1m])
|
|
-- {} 0
|
|
tql eval (55, 55, '1s') stdvar_over_time(metric[1m]);
|
|
|
|
-- eval instant at 55s stddev_over_time(metric[1m])
|
|
-- {} 0
|
|
tql eval (55, 55, '1s') stddev_over_time(metric[1m]);
|
|
|
|
drop table metric;
|
|
|
|
|
|
-- Port from functions.test L632 - L680, commit 001ee2620e094970e5657ce39275b2fccdbd1359
|
|
-- Include quantile over time
|
|
|
|
-- load 10s
|
|
-- data{test="two samples"} 0 1
|
|
-- data{test="three samples"} 0 1 2
|
|
-- data{test="uneven samples"} 0 1 4
|
|
create table data (ts timestamp(3) time index, val double, test string primary key);
|
|
|
|
insert into data values
|
|
(0, 0, "two samples"),
|
|
(10000, 1, "two samples"),
|
|
(0, 0, "three samples"),
|
|
(10000, 1, "three samples"),
|
|
(20000, 2, "three samples"),
|
|
(0, 0, "uneven samples"),
|
|
(10000, 1, "uneven samples"),
|
|
(20000, 4, "uneven samples");
|
|
|
|
-- eval instant at 1m quantile_over_time(0, data[2m])
|
|
-- {test="two samples"} 0
|
|
-- {test="three samples"} 0
|
|
-- {test="uneven samples"} 0
|
|
--
|
|
-- Prometheus `v3.9.1` updates these cases to use a larger range to avoid the (t-r) boundary.
|
|
-- See PR #13904 ("left-open and right-closed lookback/matrix selections").
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') quantile_over_time(0, data[2m]);
|
|
|
|
-- eval instant at 1m quantile_over_time(0.5, data[2m])
|
|
-- {test="two samples"} 0.5
|
|
-- {test="three samples"} 1
|
|
-- {test="uneven samples"} 1
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') quantile_over_time(0.5, data[2m]);
|
|
|
|
-- eval instant at 1m quantile_over_time(0.75, data[2m])
|
|
-- {test="two samples"} 0.75
|
|
-- {test="three samples"} 1.5
|
|
-- {test="uneven samples"} 2.5
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') quantile_over_time(0.75, data[2m]);
|
|
|
|
-- eval instant at 1m quantile_over_time(0.8, data[2m])
|
|
-- {test="two samples"} 0.8
|
|
-- {test="three samples"} 1.6
|
|
-- {test="uneven samples"} 2.8
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') quantile_over_time(0.8, data[2m]);
|
|
|
|
-- eval instant at 1m quantile_over_time(1, data[2m])
|
|
-- {test="two samples"} 1
|
|
-- {test="three samples"} 2
|
|
-- {test="uneven samples"} 4
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') quantile_over_time(1, data[2m]);
|
|
|
|
-- eval instant at 1m quantile_over_time(-1, data[2m])
|
|
-- {test="two samples"} -Inf
|
|
-- {test="three samples"} -Inf
|
|
-- {test="uneven samples"} -Inf
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') quantile_over_time(-1, data[2m]);
|
|
|
|
-- eval instant at 1m quantile_over_time(2, data[2m])
|
|
-- {test="two samples"} +Inf
|
|
-- {test="three samples"} +Inf
|
|
-- {test="uneven samples"} +Inf
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') quantile_over_time(2, data[2m]);
|
|
|
|
-- eval instant at 1m (quantile_over_time(2, (data[2m])))
|
|
-- {test="two samples"} +Inf
|
|
-- {test="three samples"} +Inf
|
|
-- {test="uneven samples"} +Inf
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') (quantile_over_time(2, (data[2m])));
|
|
|
|
drop table data;
|
|
|
|
-- Port from functions.test L773 - L802, commit 001ee2620e094970e5657ce39275b2fccdbd1359
|
|
-- Include max/min/last over time
|
|
|
|
-- load 10s
|
|
-- data{type="numbers"} 2 0 3
|
|
-- data{type="some_nan"} 2 0 NaN
|
|
-- data{type="some_nan2"} 2 NaN 1
|
|
-- data{type="some_nan3"} NaN 0 1
|
|
-- data{type="only_nan"} NaN NaN NaN
|
|
create table data (ts timestamp(3) time index, val double, ty string primary key);
|
|
|
|
insert into data values
|
|
(0, 2::double, 'numbers'),
|
|
(10000, 0::double, 'numbers'),
|
|
(20000, 3::double, 'numbers'),
|
|
(0, 2::double, 'some_nan'),
|
|
(10000, 0::double, 'some_nan'),
|
|
(20000, 'NaN'::double, 'some_nan'),
|
|
(0, 2::double, 'some_nan2'),
|
|
(10000, 'NaN'::double, 'some_nan2'),
|
|
(20000, 1::double, 'some_nan2'),
|
|
(0, 'NaN'::double, 'some_nan3'),
|
|
(10000, 0::double, 'some_nan3'),
|
|
(20000, 1::double, 'some_nan3'),
|
|
(0, 'NaN'::double, 'only_nan'),
|
|
(10000, 'NaN'::double, 'only_nan'),
|
|
(20000, 'NaN'::double, 'only_nan');
|
|
|
|
-- eval instant at 1m min_over_time(data[2m])
|
|
-- {type="numbers"} 0
|
|
-- {type="some_nan"} 0
|
|
-- {type="some_nan2"} 1
|
|
-- {type="some_nan3"} 0
|
|
-- {type="only_nan"} NaN
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') min_over_time(data[2m]);
|
|
|
|
-- eval instant at 1m max_over_time(data[2m])
|
|
-- {type="numbers"} 3
|
|
-- {type="some_nan"} 2
|
|
-- {type="some_nan2"} 2
|
|
-- {type="some_nan3"} 1
|
|
-- {type="only_nan"} NaN
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') max_over_time(data[2m]);
|
|
|
|
-- eval instant at 1m last_over_time(data[2m])
|
|
-- data{type="numbers"} 3
|
|
-- data{type="some_nan"} NaN
|
|
-- data{type="some_nan2"} 1
|
|
-- data{type="some_nan3"} 1
|
|
-- data{type="only_nan"} NaN
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (60, 60, '1s') last_over_time(data[2m]);
|
|
|
|
drop table data;
|
|
|
|
-- Sliding min/max regression: overlapping 30s windows expire extrema at the
|
|
-- left boundary, retain equal extrema, and end with a sparse empty window.
|
|
create table moving_extrema (ts timestamp(3) time index, val double, series string primary key);
|
|
|
|
insert into moving_extrema values
|
|
(0, 5::double, 'moving'),
|
|
(10000, 1::double, 'moving'),
|
|
(20000, 4::double, 'moving'),
|
|
(30000, 4::double, 'moving'),
|
|
(40000, 2::double, 'moving'),
|
|
(60000, 3::double, 'moving');
|
|
|
|
-- eval range from 20s to 100s min_over_time(moving_extrema[30s]); 90s and 100s are empty.
|
|
-- {series="moving"} 1 1 2 2 2 3 3
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (20, 100, '10s') min_over_time(moving_extrema[30s]);
|
|
|
|
-- eval range from 20s to 100s max_over_time(moving_extrema[30s]); 90s and 100s are empty.
|
|
-- {series="moving"} 5 4 4 4 3 3 3
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (20, 100, '10s') max_over_time(moving_extrema[30s]);
|
|
|
|
drop table moving_extrema;
|
|
|
|
-- Dense sliding min/max: 40-sample windows advancing 5 samples, the shape the UDF
|
|
-- reuses candidates for rather than rescanning. Values follow the timestamp, so each
|
|
-- window's minimum is its oldest sample and its maximum is its newest, and both
|
|
-- extrema expire on every step.
|
|
create table dense_extrema (ts timestamp_s time index, val double, series string primary key);
|
|
|
|
insert into dense_extrema values (0, 0::double, 'dense');
|
|
|
|
-- Doubling eight times gives 256 rows at a one-second cadence, with val = ts.
|
|
insert into dense_extrema select to_unixtime(ts) + 1, val + 1, series from dense_extrema;
|
|
|
|
insert into dense_extrema select to_unixtime(ts) + 2, val + 2, series from dense_extrema;
|
|
|
|
insert into dense_extrema select to_unixtime(ts) + 4, val + 4, series from dense_extrema;
|
|
|
|
insert into dense_extrema select to_unixtime(ts) + 8, val + 8, series from dense_extrema;
|
|
|
|
insert into dense_extrema select to_unixtime(ts) + 16, val + 16, series from dense_extrema;
|
|
|
|
insert into dense_extrema select to_unixtime(ts) + 32, val + 32, series from dense_extrema;
|
|
|
|
insert into dense_extrema select to_unixtime(ts) + 64, val + 64, series from dense_extrema;
|
|
|
|
insert into dense_extrema select to_unixtime(ts) + 128, val + 128, series from dense_extrema;
|
|
|
|
select count(*), min(val), max(val) from dense_extrema;
|
|
|
|
-- {series="dense"} 61 66 71 76 81 86 91 96 101 106 111 116 121
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (100, 160, '5s') min_over_time(dense_extrema[40s]);
|
|
|
|
-- {series="dense"} 100 105 110 115 120 125 130 135 140 145 150 155 160
|
|
-- SQLNESS SORT_RESULT 2 1
|
|
tql eval (100, 160, '5s') max_over_time(dense_extrema[40s]);
|
|
|
|
drop table dense_extrema;
|