mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-09-13 08:52:15 +00:00
* fix(query): push down PromQL cast filters Signed-off-by: discord9 <discord9@163.com> * test(query): cover cast preimage pushdown Signed-off-by: discord9 <discord9@163.com> * test(query): expand cast preimage coverage Signed-off-by: discord9 <discord9@163.com> * test(query): compare cast normalization rules Signed-off-by: discord9 <discord9@163.com> * test(query): update cast pushdown sqlness plans Signed-off-by: discord9 <discord9@163.com> --------- Signed-off-by: discord9 <discord9@163.com>
258 lines
21 KiB
Plaintext
258 lines
21 KiB
Plaintext
CREATE TABLE host_sec (
|
|
ts timestamp(0) time index,
|
|
host STRING PRIMARY KEY,
|
|
val DOUBLE,
|
|
);
|
|
|
|
Affected Rows: 0
|
|
|
|
INSERT INTO TABLE host_sec VALUES
|
|
(0, 'host1', 1),
|
|
(0, 'host2', 2),
|
|
(5, 'host1', 3),
|
|
(5, 'host2', 4),
|
|
(10, 'host1', 5),
|
|
(10, 'host2', 6),
|
|
(15, 'host1', 7),
|
|
(15, 'host2', 8);
|
|
|
|
Affected Rows: 8
|
|
|
|
CREATE TABLE host_micro (
|
|
ts timestamp(6) time index,
|
|
host STRING PRIMARY KEY,
|
|
val DOUBLE,
|
|
);
|
|
|
|
Affected Rows: 0
|
|
|
|
INSERT INTO TABLE host_micro VALUES
|
|
(0, 'host1', 1),
|
|
(0, 'host2', 2),
|
|
(5000000, 'host1', 3),
|
|
(5000000, 'host2', 4),
|
|
(10000000, 'host1', 5),
|
|
(10000000, 'host2', 6),
|
|
(15000000, 'host1', 7),
|
|
(15000000, 'host2', 8);
|
|
|
|
Affected Rows: 8
|
|
|
|
CREATE TABLE host_nano (
|
|
ts timestamp(9) time index,
|
|
host STRING PRIMARY KEY,
|
|
val DOUBLE,
|
|
);
|
|
|
|
Affected Rows: 0
|
|
|
|
INSERT INTO TABLE host_nano VALUES
|
|
(0, 'host1', 1),
|
|
(0, 'host2', 2),
|
|
(5000000000, 'host1', 3),
|
|
(5000000000, 'host2', 4),
|
|
(10000000000, 'host1', 5),
|
|
(10000000000, 'host2', 6),
|
|
(15000000000, 'host1', 7),
|
|
(15000000000, 'host2', 8);
|
|
|
|
Affected Rows: 8
|
|
|
|
-- Test on Timestamps of different precisions
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (0, 15, '5s') host_sec{host="host1"};
|
|
|
|
+-----+-------+---------------------+
|
|
| val | host | ts |
|
|
+-----+-------+---------------------+
|
|
| 1.0 | host1 | 1970-01-01T00:00:00 |
|
|
| 3.0 | host1 | 1970-01-01T00:00:05 |
|
|
| 5.0 | host1 | 1970-01-01T00:00:10 |
|
|
| 7.0 | host1 | 1970-01-01T00:00:15 |
|
|
+-----+-------+---------------------+
|
|
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (0, 15, '5s') avg_over_time(host_sec{host="host1"}[5s]);
|
|
|
|
+---------------------+----------------------------------+-------+
|
|
| ts | prom_avg_over_time(ts_range,val) | host |
|
|
+---------------------+----------------------------------+-------+
|
|
| 1970-01-01T00:00:00 | 1.0 | host1 |
|
|
| 1970-01-01T00:00:05 | 3.0 | host1 |
|
|
| 1970-01-01T00:00:10 | 5.0 | host1 |
|
|
| 1970-01-01T00:00:15 | 7.0 | host1 |
|
|
+---------------------+----------------------------------+-------+
|
|
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (0, 15, '5s') host_micro{host="host1"};
|
|
|
|
+-----+-------+---------------------+
|
|
| val | host | ts |
|
|
+-----+-------+---------------------+
|
|
| 1.0 | host1 | 1970-01-01T00:00:00 |
|
|
| 3.0 | host1 | 1970-01-01T00:00:05 |
|
|
| 5.0 | host1 | 1970-01-01T00:00:10 |
|
|
| 7.0 | host1 | 1970-01-01T00:00:15 |
|
|
+-----+-------+---------------------+
|
|
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (0, 15, '5s') avg_over_time(host_micro{host="host1"}[5s]);
|
|
|
|
+---------------------+----------------------------------+-------+
|
|
| ts | prom_avg_over_time(ts_range,val) | host |
|
|
+---------------------+----------------------------------+-------+
|
|
| 1970-01-01T00:00:00 | 1.0 | host1 |
|
|
| 1970-01-01T00:00:05 | 3.0 | host1 |
|
|
| 1970-01-01T00:00:10 | 5.0 | host1 |
|
|
| 1970-01-01T00:00:15 | 7.0 | host1 |
|
|
+---------------------+----------------------------------+-------+
|
|
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (0, 15, '5s') host_sec{host="host1"} + host_micro{host="host1"};
|
|
|
|
+-------+---------------------+-------------------------------+
|
|
| host | ts | host_sec.val + host_micro.val |
|
|
+-------+---------------------+-------------------------------+
|
|
| host1 | 1970-01-01T00:00:00 | 2.0 |
|
|
| host1 | 1970-01-01T00:00:05 | 6.0 |
|
|
| host1 | 1970-01-01T00:00:10 | 10.0 |
|
|
| host1 | 1970-01-01T00:00:15 | 14.0 |
|
|
+-------+---------------------+-------------------------------+
|
|
|
|
-- SQLNESS SORT_RESULT 3 1
|
|
TQL EVAL (0, 15, '5s') avg_over_time(host_sec{host="host1"}[5s]) + avg_over_time(host_micro{host="host1"}[5s]);
|
|
|
|
+-------+---------------------+-----------------------------------------------------------------------------------------+
|
|
| host | ts | host_sec.prom_avg_over_time(ts_range,val) + host_micro.prom_avg_over_time(ts_range,val) |
|
|
+-------+---------------------+-----------------------------------------------------------------------------------------+
|
|
| host1 | 1970-01-01T00:00:00 | 2.0 |
|
|
| host1 | 1970-01-01T00:00:05 | 6.0 |
|
|
| host1 | 1970-01-01T00:00:10 | 10.0 |
|
|
| host1 | 1970-01-01T00:00:15 | 14.0 |
|
|
+-------+---------------------+-----------------------------------------------------------------------------------------+
|
|
|
|
-- Verify that PromQL time predicates on non-millisecond time indexes are
|
|
-- pushed into the scan as native timestamp range filters.
|
|
-- Original instant selector filter is built on the millisecond alias:
|
|
-- host = "host1" AND ts_ms >= -299999ms AND ts_ms <= 10000ms
|
|
-- After pushing through `CAST(raw_ts AS Timestamp(ms)) AS ts` and applying
|
|
-- DataFusion cast preimage, it becomes a native half-open range on raw_ts.
|
|
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
|
|
-- SQLNESS REPLACE (peers.*) REDACTED
|
|
-- SQLNESS REPLACE (Hash.*) REDACTED
|
|
-- SQLNESS REPLACE (RepartitionExec:.*) RepartitionExec: REDACTED
|
|
-- SQLNESS REPLACE host_micro.__table_id\s*=\s*UInt32\(\d+\) host_micro.__table_id=UInt32(REDACTED)
|
|
-- SQLNESS REPLACE host_nano.__table_id\s*=\s*UInt32\(\d+\) host_nano.__table_id=UInt32(REDACTED)
|
|
TQL EXPLAIN (0, 10, '5s') host_micro{host="host1"};
|
|
|
|
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
| plan_type | plan |
|
|
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
| logical_plan | MergeScan [is_placeholder=false, remote_input=[ |
|
|
| | PromInstantManipulate: range=[0..10000], lookback=[300000], interval=[5000], time index=[ts] |
|
|
| | PromSeriesDivide: tags=["host"] |
|
|
| | Sort: host_micro.host ASC NULLS FIRST, host_micro.ts ASC NULLS FIRST |
|
|
| | Projection: host_micro.val, host_micro.host, CAST(host_micro.ts AS Timestamp(ms)) AS ts |
|
|
| | Filter: host_micro.host = Utf8("host1") AND host_micro.ts >= TimestampMicrosecond(-299999999, None) AND host_micro.ts < TimestampMicrosecond(10001000, None) |
|
|
| | TableScan: host_micro, partial_filters=[host_micro.host = Utf8("host1"), host_micro.ts >= TimestampMicrosecond(-299999999, None), host_micro.ts < TimestampMicrosecond(10001000, None)] |
|
|
| | ]] |
|
|
| physical_plan | CooperativeExec |
|
|
| | MergeScanExec: REDACTED
|
|
| | |
|
|
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
-- The same instant-selector cast-preimage path should work for nanosecond indexes.
|
|
-- Expected native bounds: ts_ns >= -299999999999ns AND ts_ns < 10001000000ns.
|
|
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
|
|
-- SQLNESS REPLACE (peers.*) REDACTED
|
|
-- SQLNESS REPLACE (Hash.*) REDACTED
|
|
-- SQLNESS REPLACE (RepartitionExec:.*) RepartitionExec: REDACTED
|
|
-- SQLNESS REPLACE host_nano.__table_id\s*=\s*UInt32\(\d+\) host_nano.__table_id=UInt32(REDACTED)
|
|
TQL EXPLAIN (0, 10, '5s') host_nano{host="host1"};
|
|
|
|
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
| plan_type | plan |
|
|
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
| logical_plan | MergeScan [is_placeholder=false, remote_input=[ |
|
|
| | PromInstantManipulate: range=[0..10000], lookback=[300000], interval=[5000], time index=[ts] |
|
|
| | PromSeriesDivide: tags=["host"] |
|
|
| | Sort: host_nano.host ASC NULLS FIRST, host_nano.ts ASC NULLS FIRST |
|
|
| | Projection: host_nano.val, host_nano.host, CAST(host_nano.ts AS Timestamp(ms)) AS ts |
|
|
| | Filter: host_nano.host = Utf8("host1") AND host_nano.ts >= TimestampNanosecond(-299999999999, None) AND host_nano.ts < TimestampNanosecond(10001000000, None) |
|
|
| | TableScan: host_nano, partial_filters=[host_nano.host = Utf8("host1"), host_nano.ts >= TimestampNanosecond(-299999999999, None), host_nano.ts < TimestampNanosecond(10001000000, None)] |
|
|
| | ]] |
|
|
| physical_plan | CooperativeExec |
|
|
| | MergeScanExec: REDACTED
|
|
| | |
|
|
+---------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
-- Range selectors use their range window instead of the default lookback.
|
|
-- Original range selector filter for [5s]:
|
|
-- host = "host1" AND ts_ms >= -4999ms AND ts_ms <= 10000ms
|
|
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
|
|
-- SQLNESS REPLACE (peers.*) REDACTED
|
|
-- SQLNESS REPLACE (Hash.*) REDACTED
|
|
-- SQLNESS REPLACE (RepartitionExec:.*) RepartitionExec: REDACTED
|
|
-- SQLNESS REPLACE host_micro.__table_id\s*=\s*UInt32\(\d+\) host_micro.__table_id=UInt32(REDACTED)
|
|
TQL EXPLAIN (0, 10, '5s') avg_over_time(host_micro{host="host1"}[5s]);
|
|
|
|
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
| plan_type | plan |
|
|
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
| logical_plan | MergeScan [is_placeholder=false, remote_input=[ |
|
|
| | Filter: prom_avg_over_time(ts_range,val) IS NOT NULL |
|
|
| | Projection: host_micro.ts, prom_avg_over_time(ts_range, val) AS prom_avg_over_time(ts_range,val), host_micro.host |
|
|
| | PromRangeManipulate: req range=[0..10000], interval=[5000], eval range=[5000], time index=[ts], values=["val"] |
|
|
| | PromSeriesNormalize: offset=[0], time index=[ts], filter NaN: [true] |
|
|
| | PromSeriesDivide: tags=["host"] |
|
|
| | Sort: host_micro.host ASC NULLS FIRST, host_micro.ts ASC NULLS FIRST |
|
|
| | Projection: host_micro.val, host_micro.host, CAST(host_micro.ts AS Timestamp(ms)) AS ts |
|
|
| | Filter: host_micro.host = Utf8("host1") AND host_micro.ts >= TimestampMicrosecond(-4999999, None) AND host_micro.ts < TimestampMicrosecond(10001000, None) |
|
|
| | TableScan: host_micro, partial_filters=[host_micro.host = Utf8("host1"), host_micro.ts >= TimestampMicrosecond(-4999999, None), host_micro.ts < TimestampMicrosecond(10001000, None)] |
|
|
| | ]] |
|
|
| physical_plan | CooperativeExec |
|
|
| | MergeScanExec: REDACTED
|
|
| | |
|
|
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
-- The same range-selector cast-preimage path should work for nanosecond indexes.
|
|
-- Expected native bounds: ts_ns >= -4999999999ns AND ts_ns < 10001000000ns.
|
|
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
|
|
-- SQLNESS REPLACE (peers.*) REDACTED
|
|
-- SQLNESS REPLACE (Hash.*) REDACTED
|
|
-- SQLNESS REPLACE (RepartitionExec:.*) RepartitionExec: REDACTED
|
|
-- SQLNESS REPLACE host_nano.__table_id\s*=\s*UInt32\(\d+\) host_nano.__table_id=UInt32(REDACTED)
|
|
TQL EXPLAIN (0, 10, '5s') avg_over_time(host_nano{host="host1"}[5s]);
|
|
|
|
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
| plan_type | plan |
|
|
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
| logical_plan | MergeScan [is_placeholder=false, remote_input=[ |
|
|
| | Filter: prom_avg_over_time(ts_range,val) IS NOT NULL |
|
|
| | Projection: host_nano.ts, prom_avg_over_time(ts_range, val) AS prom_avg_over_time(ts_range,val), host_nano.host |
|
|
| | PromRangeManipulate: req range=[0..10000], interval=[5000], eval range=[5000], time index=[ts], values=["val"] |
|
|
| | PromSeriesNormalize: offset=[0], time index=[ts], filter NaN: [true] |
|
|
| | PromSeriesDivide: tags=["host"] |
|
|
| | Sort: host_nano.host ASC NULLS FIRST, host_nano.ts ASC NULLS FIRST |
|
|
| | Projection: host_nano.val, host_nano.host, CAST(host_nano.ts AS Timestamp(ms)) AS ts |
|
|
| | Filter: host_nano.host = Utf8("host1") AND host_nano.ts >= TimestampNanosecond(-4999999999, None) AND host_nano.ts < TimestampNanosecond(10001000000, None) |
|
|
| | TableScan: host_nano, partial_filters=[host_nano.host = Utf8("host1"), host_nano.ts >= TimestampNanosecond(-4999999999, None), host_nano.ts < TimestampNanosecond(10001000000, None)] |
|
|
| | ]] |
|
|
| physical_plan | CooperativeExec |
|
|
| | MergeScanExec: REDACTED
|
|
| | |
|
|
+---------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
|
|
|
DROP TABLE host_sec;
|
|
|
|
Affected Rows: 0
|
|
|
|
DROP TABLE host_micro;
|
|
|
|
Affected Rows: 0
|
|
|
|
DROP TABLE host_nano;
|
|
|
|
Affected Rows: 0
|
|
|