mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-09-22 13:15:34 +00:00
Review follow-up. Two things surfaced once range functions started returning NULL for a window without samples. The filter after a function call required every field column to be non-NULL, so on a multi-field table one field with no samples in a window would drop the other fields' results with it. It now keeps a row when any field has a sample, which is the shape a selector already emits. On a single field column the two predicates are identical. `quantile_over_time` returned NaN rather than NULL for a window without samples, so the row survived that filter. Prometheus returns an empty vector there, so the emptiness check now sits in the range UDF; the shared quantile kernel still yields NaN for an empty slice, matching upstream's `quantile()` helper that `quantile_aggr` depends on. Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
94 lines
2.6 KiB
SQL
94 lines
2.6 KiB
SQL
CREATE TABLE null_samples (
|
|
ts TIMESTAMP(3) TIME INDEX,
|
|
"region" STRING,
|
|
host STRING,
|
|
val DOUBLE,
|
|
PRIMARY KEY ("region", host)
|
|
);
|
|
|
|
INSERT INTO null_samples VALUES
|
|
(0, 'empty', 'e', NULL),
|
|
(1000, 'empty', 'e', NULL),
|
|
(0, 'ok', 'o', 1.0),
|
|
(1000, 'ok', 'o', 2.0),
|
|
(2000, 'ok', 'o', 3.0);
|
|
|
|
-- The `empty` series has no sample in any window, so it must not reach the aggregation.
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (0, 15, '1s') avg by (region) (rate(null_samples[4s]));
|
|
|
|
DROP TABLE null_samples;
|
|
|
|
CREATE TABLE sparse_samples (
|
|
ts TIMESTAMP(3) TIME INDEX,
|
|
host STRING PRIMARY KEY,
|
|
val DOUBLE
|
|
);
|
|
|
|
INSERT INTO sparse_samples VALUES
|
|
(0, 'a', 1.0),
|
|
(1000, 'a', NULL),
|
|
(2000, 'a', NULL),
|
|
(3000, 'a', 4.0);
|
|
|
|
-- Every window below holds two samples, 1.0 at 0s and 4.0 at 3s.
|
|
TQL EVAL (3, 3, '1s') rate(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') increase(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') delta(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') idelta(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') irate(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') changes(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') resets(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') avg_over_time(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') stddev_over_time(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') stdvar_over_time(sparse_samples[4s]);
|
|
|
|
TQL EVAL (3, 3, '1s') quantile_over_time(0.5, sparse_samples[4s]);
|
|
|
|
-- A window whose only slot is NULL holds no sample.
|
|
TQL EVAL (1, 1, '1s') rate(sparse_samples[1s]);
|
|
|
|
TQL EVAL (1, 1, '1s') changes(sparse_samples[1s]);
|
|
|
|
-- Prometheus returns an empty vector for a range without samples, not NaN.
|
|
TQL EVAL (1, 1, '1s') quantile_over_time(0.5, sparse_samples[1s]);
|
|
|
|
DROP TABLE sparse_samples;
|
|
|
|
CREATE TABLE multi_field (
|
|
ts TIMESTAMP(3) TIME INDEX,
|
|
host STRING PRIMARY KEY,
|
|
f1 DOUBLE,
|
|
f2 DOUBLE
|
|
);
|
|
|
|
INSERT INTO multi_field VALUES
|
|
(0, 'a', 1.0, 10.0),
|
|
(1000, 'a', 2.0, NULL),
|
|
(2000, 'a', 3.0, NULL),
|
|
(3000, 'a', 4.0, 40.0);
|
|
|
|
-- f1 and f2 share the same rows but have samples at different timestamps. Dropping the rows
|
|
-- where f2 is NULL would also drop two of f1's samples, so each field is counted separately.
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (3, 3, '1s') rate(multi_field[4s]);
|
|
|
|
-- f1 has two samples in this window and f2 only one, so f1 keeps its result while f2 is NULL.
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (1, 1, '1s') rate(multi_field[4s]);
|
|
|
|
-- A selector emits the same shape: the row stays, the field without a sample is NULL.
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (1, 1, '1s') multi_field;
|
|
|
|
DROP TABLE multi_field;
|