Compare commits

...

1 Commits

Author SHA1 Message Date
Weny Xu
4bb9ceb63b chore: cherry pick patches to release/v0.17.0 branch (#7024)
* fix: print the output message of the error in admin fn macro (#6994)

Signed-off-by: evenyag <realevenyag@gmail.com>
Signed-off-by: discord9 <discord9@163.com>

* fix: make EXPIRE (keyword) parsing case-insensitive, when creating flow (#6997)

fix: make EXPIRE keyword case-insensitive in CREATE FLOW parser

Signed-off-by: Shyamnatesan <shyamnatesan21@gmail.com>
Signed-off-by: discord9 <discord9@163.com>

* fix: promql range function has incorrect timestamps (#7006)

* fix: promql range function has incorrect timestamps

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>

* simplify

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>

---------

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>
Signed-off-by: discord9 <discord9@163.com>

* fix: incorrect timestamp resolution in information_schema.partitions table (#7004)

* fix: incorrect timestamp resolution in information_schema.partitions table

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>

* use second for all fields in partitions table

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>

* update sqlness result

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>

---------

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>
Signed-off-by: discord9 <discord9@163.com>

* fix: match promql column reference in case sensitive way (#7013)

Signed-off-by: Ruihang Xia <waynestxia@gmail.com>
Signed-off-by: discord9 <discord9@163.com>

* fix: group by expr not as column in step aggr (#7008)

* fix: group by expr not as column

Signed-off-by: discord9 <discord9@163.com>

* test: dist analyzer date_bin

Signed-off-by: discord9 <discord9@163.com>

* ???fix wip

Signed-off-by: discord9 <discord9@163.com>

* fix: deduce using correct input fields

Signed-off-by: discord9 <discord9@163.com>

* refactor: clearer wrapper

Signed-off-by: discord9 <discord9@163.com>

* chore: update sqlness

Signed-off-by: discord9 <discord9@163.com>

* chore: per review

Signed-off-by: discord9 <discord9@163.com>

* chore: per review

Signed-off-by: discord9 <discord9@163.com>

* chore: rm todo

Signed-off-by: discord9 <discord9@163.com>

---------

Signed-off-by: discord9 <discord9@163.com>

* fix: skip placeholder when partition columns (#7020)

Signed-off-by: discord9 <discord9@163.com>

* chore: add function for getting started on metasrv (#7022)

Signed-off-by: shuiyisong <xixing.sys@gmail.com>
Signed-off-by: discord9 <discord9@163.com>

* fix: not step when aggr have order by/filter (#7015)

* fix: not applied

Signed-off-by: discord9 <discord9@163.com>

* chore: per review

Signed-off-by: discord9 <discord9@163.com>

* test: confirm order by not push down

Signed-off-by: discord9 <discord9@163.com>

---------

Signed-off-by: discord9 <discord9@163.com>

* feat: supports expression in TQL params (#7014)

* feat: supports expression in TQL params

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: by cr comments

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: comment

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

* chore: by cr comments

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>

---------

Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
Signed-off-by: discord9 <discord9@163.com>

* feat: update dashboard to v0.11.6 (#7026)

Co-authored-by: ZonaHex <ZonaHex@users.noreply.github.com>
Signed-off-by: discord9 <discord9@163.com>

* fix: step aggr merge phase not order nor filter (#6998)

* fix: not order

Signed-off-by: discord9 <discord9@163.com>

* test: redacted

Signed-off-by: discord9 <discord9@163.com>

* feat: fix up state wrapper

Signed-off-by: discord9 <discord9@163.com>

* df last_value state not as promised!

Signed-off-by: discord9 <discord9@163.com>

* fix?: could fix better

Signed-off-by: discord9 <discord9@163.com>

* test: unstable result

Signed-off-by: discord9 <discord9@163.com>

* fix: work around by fixing state

Signed-off-by: discord9 <discord9@163.com>

* chore: after rebase fix

Signed-off-by: discord9 <discord9@163.com>

* chore: finish some todo

Signed-off-by: discord9 <discord9@163.com>

* chore: per copilot

Signed-off-by: discord9 <discord9@163.com>

* refactor: not fix but just notify mismatch

Signed-off-by: discord9 <discord9@163.com>

* chore: warn -> debug state mismatch

Signed-off-by: discord9 <discord9@163.com>

* chore: refine error msg

Signed-off-by: discord9 <discord9@163.com>

* test: sqlness add last_value date_bin test

Signed-off-by: discord9 <discord9@163.com>

* ?: substrait order by decode failure

Signed-off-by: discord9 <discord9@163.com>

* unit test reproduce that

Signed-off-by: discord9 <discord9@163.com>

* feat: support state wrapper's order serde in substrait

Signed-off-by: discord9 <discord9@163.com>

* refactor: stuff

Signed-off-by: discord9 <discord9@163.com>

* test: standalone/distributed different exec

Signed-off-by: discord9 <discord9@163.com>

* fmt

Signed-off-by: discord9 <discord9@163.com>

* chore: per review

Signed-off-by: discord9 <discord9@163.com>

* refactor: closure

Signed-off-by: discord9 <discord9@163.com>

* test: first value order by

Signed-off-by: discord9 <discord9@163.com>

* refactor: per cr

Signed-off-by: discord9 <discord9@163.com>

* feat: ScanHint last_value last row selector

Signed-off-by: discord9 <discord9@163.com>

* docs: per cr

Signed-off-by: discord9 <discord9@163.com>

---------

Signed-off-by: discord9 <discord9@163.com>

* chore: bump version to 0.17.2

Signed-off-by: WenyXu <wenymedia@gmail.com>
Signed-off-by: discord9 <discord9@163.com>

* chore: not warning

Signed-off-by: discord9 <discord9@163.com>

---------

Signed-off-by: evenyag <realevenyag@gmail.com>
Signed-off-by: discord9 <discord9@163.com>
Signed-off-by: Shyamnatesan <shyamnatesan21@gmail.com>
Signed-off-by: Ruihang Xia <waynestxia@gmail.com>
Signed-off-by: shuiyisong <xixing.sys@gmail.com>
Signed-off-by: Dennis Zhuang <killme2008@gmail.com>
Signed-off-by: WenyXu <wenymedia@gmail.com>
Co-authored-by: Yingwen <realevenyag@gmail.com>
Co-authored-by: shyam <43544082+Shyamnatesan@users.noreply.github.com>
Co-authored-by: Ruihang Xia <waynestxia@gmail.com>
Co-authored-by: discord9 <55937128+discord9@users.noreply.github.com>
Co-authored-by: shuiyisong <113876041+shuiyisong@users.noreply.github.com>
Co-authored-by: dennis zhuang <killme2008@gmail.com>
Co-authored-by: ZonaHe <zonahe@qq.com>
Co-authored-by: ZonaHex <ZonaHex@users.noreply.github.com>
Co-authored-by: discord9 <discord9@163.com>
2025-09-28 16:21:06 +08:00
53 changed files with 6291 additions and 578 deletions

157
Cargo.lock generated
View File

@@ -218,7 +218,7 @@ checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c"
[[package]]
name = "api"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"common-base",
"common-decimal",
@@ -737,7 +737,7 @@ dependencies = [
[[package]]
name = "auth"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -1387,7 +1387,7 @@ dependencies = [
[[package]]
name = "cache"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"catalog",
"common-error",
@@ -1422,7 +1422,7 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "catalog"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"arrow",
@@ -1763,7 +1763,7 @@ checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675"
[[package]]
name = "cli"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-stream",
"async-trait",
@@ -1807,7 +1807,7 @@ dependencies = [
"session",
"snafu 0.8.6",
"store-api",
"substrait 0.17.1",
"substrait 0.17.2",
"table",
"tempfile",
"tokio",
@@ -1816,7 +1816,7 @@ dependencies = [
[[package]]
name = "client"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"arc-swap",
@@ -1848,7 +1848,7 @@ dependencies = [
"serde_json",
"snafu 0.8.6",
"store-api",
"substrait 0.17.1",
"substrait 0.17.2",
"substrait 0.37.3",
"tokio",
"tokio-stream",
@@ -1889,7 +1889,7 @@ dependencies = [
[[package]]
name = "cmd"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-trait",
"auth",
@@ -1951,7 +1951,7 @@ dependencies = [
"snafu 0.8.6",
"stat",
"store-api",
"substrait 0.17.1",
"substrait 0.17.2",
"table",
"temp-env",
"tempfile",
@@ -1997,7 +1997,7 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335"
[[package]]
name = "common-base"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"anymap2",
"async-trait",
@@ -2019,11 +2019,11 @@ dependencies = [
[[package]]
name = "common-catalog"
version = "0.17.1"
version = "0.17.2"
[[package]]
name = "common-config"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"common-base",
"common-error",
@@ -2049,7 +2049,7 @@ dependencies = [
[[package]]
name = "common-datasource"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"arrow",
"arrow-schema",
@@ -2084,7 +2084,7 @@ dependencies = [
[[package]]
name = "common-decimal"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"bigdecimal 0.4.8",
"common-error",
@@ -2097,7 +2097,7 @@ dependencies = [
[[package]]
name = "common-error"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"common-macro",
"http 1.3.1",
@@ -2108,7 +2108,7 @@ dependencies = [
[[package]]
name = "common-event-recorder"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -2130,7 +2130,7 @@ dependencies = [
[[package]]
name = "common-frontend"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -2152,7 +2152,7 @@ dependencies = [
[[package]]
name = "common-function"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"ahash 0.8.12",
"api",
@@ -2210,7 +2210,7 @@ dependencies = [
[[package]]
name = "common-greptimedb-telemetry"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-trait",
"common-runtime",
@@ -2227,7 +2227,7 @@ dependencies = [
[[package]]
name = "common-grpc"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"arrow-flight",
@@ -2260,7 +2260,7 @@ dependencies = [
[[package]]
name = "common-grpc-expr"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"common-base",
@@ -2280,7 +2280,7 @@ dependencies = [
[[package]]
name = "common-macro"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"greptime-proto",
"once_cell",
@@ -2291,7 +2291,7 @@ dependencies = [
[[package]]
name = "common-mem-prof"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"anyhow",
"common-error",
@@ -2307,7 +2307,7 @@ dependencies = [
[[package]]
name = "common-meta"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"anymap2",
"api",
@@ -2379,7 +2379,7 @@ dependencies = [
[[package]]
name = "common-options"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"common-grpc",
"humantime-serde",
@@ -2388,11 +2388,11 @@ dependencies = [
[[package]]
name = "common-plugins"
version = "0.17.1"
version = "0.17.2"
[[package]]
name = "common-pprof"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"common-error",
"common-macro",
@@ -2404,7 +2404,7 @@ dependencies = [
[[package]]
name = "common-procedure"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-stream",
@@ -2433,7 +2433,7 @@ dependencies = [
[[package]]
name = "common-procedure-test"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-trait",
"common-procedure",
@@ -2443,7 +2443,7 @@ dependencies = [
[[package]]
name = "common-query"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -2468,7 +2468,7 @@ dependencies = [
[[package]]
name = "common-recordbatch"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"arc-swap",
"common-error",
@@ -2489,7 +2489,7 @@ dependencies = [
[[package]]
name = "common-runtime"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-trait",
"clap 4.5.40",
@@ -2518,7 +2518,7 @@ dependencies = [
[[package]]
name = "common-session"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"serde",
"strum 0.27.1",
@@ -2526,7 +2526,7 @@ dependencies = [
[[package]]
name = "common-sql"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"common-base",
"common-decimal",
@@ -2544,7 +2544,7 @@ dependencies = [
[[package]]
name = "common-telemetry"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"backtrace",
"common-base",
@@ -2573,7 +2573,7 @@ dependencies = [
[[package]]
name = "common-test-util"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"client",
"common-grpc",
@@ -2586,7 +2586,7 @@ dependencies = [
[[package]]
name = "common-time"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"arrow",
"chrono",
@@ -2604,7 +2604,7 @@ dependencies = [
[[package]]
name = "common-version"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"build-data",
"cargo-manifest",
@@ -2615,7 +2615,7 @@ dependencies = [
[[package]]
name = "common-wal"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"common-base",
"common-error",
@@ -2638,7 +2638,7 @@ dependencies = [
[[package]]
name = "common-workload"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"common-telemetry",
"serde",
@@ -3865,7 +3865,7 @@ dependencies = [
[[package]]
name = "datanode"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"arrow-flight",
@@ -3918,7 +3918,7 @@ dependencies = [
"session",
"snafu 0.8.6",
"store-api",
"substrait 0.17.1",
"substrait 0.17.2",
"table",
"tokio",
"toml 0.8.23",
@@ -3928,7 +3928,7 @@ dependencies = [
[[package]]
name = "datatypes"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"arrow",
"arrow-array",
@@ -4602,7 +4602,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "file-engine"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -4734,7 +4734,7 @@ checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8"
[[package]]
name = "flow"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"arrow",
@@ -4801,7 +4801,7 @@ dependencies = [
"sql",
"store-api",
"strum 0.27.1",
"substrait 0.17.1",
"substrait 0.17.2",
"table",
"tokio",
"tonic 0.13.1",
@@ -4856,7 +4856,7 @@ checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619"
[[package]]
name = "frontend"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"arc-swap",
@@ -4919,7 +4919,7 @@ dependencies = [
"sqlparser 0.55.0-greptime",
"store-api",
"strfmt",
"substrait 0.17.1",
"substrait 0.17.2",
"table",
"tokio",
"tokio-util",
@@ -6061,7 +6061,7 @@ dependencies = [
[[package]]
name = "index"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-trait",
"asynchronous-codec",
@@ -7001,7 +7001,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]]
name = "log-query"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"chrono",
"common-error",
@@ -7013,7 +7013,7 @@ dependencies = [
[[package]]
name = "log-store"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-stream",
"async-trait",
@@ -7320,7 +7320,7 @@ dependencies = [
[[package]]
name = "meta-client"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -7348,7 +7348,7 @@ dependencies = [
[[package]]
name = "meta-srv"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -7444,7 +7444,7 @@ dependencies = [
[[package]]
name = "metric-engine"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"aquamarine",
@@ -7537,7 +7537,7 @@ dependencies = [
[[package]]
name = "mito-codec"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"bytes",
@@ -7561,7 +7561,7 @@ dependencies = [
[[package]]
name = "mito2"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"aquamarine",
@@ -8295,7 +8295,7 @@ dependencies = [
[[package]]
name = "object-store"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"anyhow",
"bytes",
@@ -8580,7 +8580,7 @@ dependencies = [
[[package]]
name = "operator"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"ahash 0.8.12",
"api",
@@ -8638,7 +8638,7 @@ dependencies = [
"sql",
"sqlparser 0.55.0-greptime",
"store-api",
"substrait 0.17.1",
"substrait 0.17.2",
"table",
"tokio",
"tokio-util",
@@ -8950,7 +8950,7 @@ dependencies = [
[[package]]
name = "partition"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -9289,7 +9289,7 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pipeline"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"ahash 0.8.12",
"api",
@@ -9445,7 +9445,7 @@ dependencies = [
[[package]]
name = "plugins"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"auth",
"clap 4.5.40",
@@ -9743,7 +9743,7 @@ dependencies = [
[[package]]
name = "promql"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"ahash 0.8.12",
"async-trait",
@@ -10026,7 +10026,7 @@ dependencies = [
[[package]]
name = "puffin"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-compression 0.4.19",
"async-trait",
@@ -10068,7 +10068,7 @@ dependencies = [
[[package]]
name = "query"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"ahash 0.8.12",
"api",
@@ -10133,7 +10133,7 @@ dependencies = [
"sql",
"sqlparser 0.55.0-greptime",
"store-api",
"substrait 0.17.1",
"substrait 0.17.2",
"table",
"tokio",
"tokio-stream",
@@ -11497,7 +11497,7 @@ dependencies = [
[[package]]
name = "servers"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"ahash 0.8.12",
"api",
@@ -11620,7 +11620,7 @@ dependencies = [
[[package]]
name = "session"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"ahash 0.8.12",
"api",
@@ -11948,7 +11948,7 @@ dependencies = [
[[package]]
name = "sql"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"arrow-buffer",
@@ -12006,7 +12006,7 @@ dependencies = [
[[package]]
name = "sqlness-runner"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-trait",
"clap 4.5.40",
@@ -12306,7 +12306,7 @@ dependencies = [
[[package]]
name = "stat"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"nix 0.30.1",
]
@@ -12319,7 +12319,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "store-api"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"aquamarine",
@@ -12466,11 +12466,12 @@ dependencies = [
[[package]]
name = "substrait"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"async-trait",
"bytes",
"common-error",
"common-function",
"common-macro",
"common-telemetry",
"datafusion",
@@ -12634,7 +12635,7 @@ dependencies = [
[[package]]
name = "table"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"async-trait",
@@ -12903,7 +12904,7 @@ checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683"
[[package]]
name = "tests-fuzz"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"arbitrary",
"async-trait",
@@ -12947,7 +12948,7 @@ dependencies = [
[[package]]
name = "tests-integration"
version = "0.17.1"
version = "0.17.2"
dependencies = [
"api",
"arrow-flight",
@@ -13019,7 +13020,7 @@ dependencies = [
"sql",
"sqlx",
"store-api",
"substrait 0.17.1",
"substrait 0.17.2",
"table",
"tempfile",
"time",

View File

@@ -73,7 +73,7 @@ members = [
resolver = "2"
[workspace.package]
version = "0.17.1"
version = "0.17.2"
edition = "2021"
license = "Apache-2.0"

View File

@@ -26,12 +26,11 @@ use datafusion::physical_plan::streaming::PartitionStream as DfPartitionStream;
use datafusion::physical_plan::SendableRecordBatchStream as DfSendableRecordBatchStream;
use datatypes::prelude::{ConcreteDataType, ScalarVectorBuilder, VectorRef};
use datatypes::schema::{ColumnSchema, Schema, SchemaRef};
use datatypes::timestamp::TimestampMicrosecond;
use datatypes::timestamp::TimestampSecond;
use datatypes::value::Value;
use datatypes::vectors::{
ConstantVector, Int64Vector, Int64VectorBuilder, MutableVector, StringVector,
StringVectorBuilder, TimestampMicrosecondVector, TimestampMicrosecondVectorBuilder,
UInt64VectorBuilder,
StringVectorBuilder, TimestampSecondVector, TimestampSecondVectorBuilder, UInt64VectorBuilder,
};
use futures::{StreamExt, TryStreamExt};
use partition::manager::PartitionInfo;
@@ -129,17 +128,17 @@ impl InformationSchemaPartitions {
ColumnSchema::new("data_free", ConcreteDataType::int64_datatype(), true),
ColumnSchema::new(
"create_time",
ConcreteDataType::timestamp_microsecond_datatype(),
ConcreteDataType::timestamp_second_datatype(),
true,
),
ColumnSchema::new(
"update_time",
ConcreteDataType::timestamp_microsecond_datatype(),
ConcreteDataType::timestamp_second_datatype(),
true,
),
ColumnSchema::new(
"check_time",
ConcreteDataType::timestamp_microsecond_datatype(),
ConcreteDataType::timestamp_second_datatype(),
true,
),
ColumnSchema::new("checksum", ConcreteDataType::int64_datatype(), true),
@@ -212,7 +211,7 @@ struct InformationSchemaPartitionsBuilder {
partition_names: StringVectorBuilder,
partition_ordinal_positions: Int64VectorBuilder,
partition_expressions: StringVectorBuilder,
create_times: TimestampMicrosecondVectorBuilder,
create_times: TimestampSecondVectorBuilder,
partition_ids: UInt64VectorBuilder,
}
@@ -232,7 +231,7 @@ impl InformationSchemaPartitionsBuilder {
partition_names: StringVectorBuilder::with_capacity(INIT_CAPACITY),
partition_ordinal_positions: Int64VectorBuilder::with_capacity(INIT_CAPACITY),
partition_expressions: StringVectorBuilder::with_capacity(INIT_CAPACITY),
create_times: TimestampMicrosecondVectorBuilder::with_capacity(INIT_CAPACITY),
create_times: TimestampSecondVectorBuilder::with_capacity(INIT_CAPACITY),
partition_ids: UInt64VectorBuilder::with_capacity(INIT_CAPACITY),
}
}
@@ -331,8 +330,8 @@ impl InformationSchemaPartitionsBuilder {
.push(Some((index + 1) as i64));
let expression = partition.partition_expr.as_ref().map(|e| e.to_string());
self.partition_expressions.push(expression.as_deref());
self.create_times.push(Some(TimestampMicrosecond::from(
table_info.meta.created_on.timestamp_millis(),
self.create_times.push(Some(TimestampSecond::from(
table_info.meta.created_on.timestamp(),
)));
self.partition_ids.push(Some(partition.id.as_u64()));
}
@@ -349,8 +348,8 @@ impl InformationSchemaPartitionsBuilder {
Arc::new(Int64Vector::from(vec![None])),
rows_num,
));
let null_timestampmicrosecond_vector = Arc::new(ConstantVector::new(
Arc::new(TimestampMicrosecondVector::from(vec![None])),
let null_timestamp_second_vector = Arc::new(ConstantVector::new(
Arc::new(TimestampSecondVector::from(vec![None])),
rows_num,
));
let partition_methods = Arc::new(ConstantVector::new(
@@ -380,8 +379,8 @@ impl InformationSchemaPartitionsBuilder {
null_i64_vector.clone(),
Arc::new(self.create_times.finish()),
// TODO(dennis): supports update_time
null_timestampmicrosecond_vector.clone(),
null_timestampmicrosecond_vector,
null_timestamp_second_vector.clone(),
null_timestamp_second_vector,
null_i64_vector,
null_string_vector.clone(),
null_string_vector.clone(),

View File

@@ -41,7 +41,12 @@ use datafusion_expr::{
use datafusion_physical_expr::aggregate::AggregateFunctionExpr;
use datatypes::arrow::datatypes::{DataType, Field};
use crate::function_registry::FunctionRegistry;
use crate::aggrs::aggr_wrapper::fix_order::FixStateUdafOrderingAnalyzer;
use crate::function_registry::{FunctionRegistry, FUNCTION_REGISTRY};
pub mod fix_order;
#[cfg(test)]
mod tests;
/// Returns the name of the state function for the given aggregate function name.
/// The state function is used to compute the state of the aggregate function.
@@ -57,6 +62,39 @@ pub fn aggr_merge_func_name(aggr_name: &str) -> String {
format!("__{}_merge", aggr_name)
}
/// Check if the given aggregate expression is steppable.
/// As in if it can be split into multiple steps:
/// i.e. on datanode first call `state(input)` then
/// on frontend call `calc(merge(state))` to get the final result.
pub fn is_all_aggr_exprs_steppable(aggr_exprs: &[Expr]) -> bool {
aggr_exprs.iter().all(|expr| {
if let Some(aggr_func) = get_aggr_func(expr) {
if aggr_func.params.distinct {
// Distinct aggregate functions are not steppable(yet).
// TODO(discord9): support distinct aggregate functions.
return false;
}
// whether the corresponding state function exists in the registry
FUNCTION_REGISTRY.is_aggr_func_exist(&aggr_state_func_name(aggr_func.func.name()))
} else {
false
}
})
}
pub fn get_aggr_func(expr: &Expr) -> Option<&datafusion_expr::expr::AggregateFunction> {
let mut expr_ref = expr;
while let Expr::Alias(alias) = expr_ref {
expr_ref = &alias.expr;
}
if let Expr::AggregateFunction(aggr_func) = expr_ref {
Some(aggr_func)
} else {
None
}
}
/// A wrapper to make an aggregate function out of the state and merge functions of the original aggregate function.
/// It contains the original aggregate function, the state functions, and the merge function.
///
@@ -74,18 +112,6 @@ pub struct StepAggrPlan {
pub lower_state: LogicalPlan,
}
pub fn get_aggr_func(expr: &Expr) -> Option<&datafusion_expr::expr::AggregateFunction> {
let mut expr_ref = expr;
while let Expr::Alias(alias) = expr_ref {
expr_ref = &alias.expr;
}
if let Expr::AggregateFunction(aggr_func) = expr_ref {
Some(aggr_func)
} else {
None
}
}
impl StateMergeHelper {
/// Register all the `state` function of supported aggregate functions.
/// Note that can't register `merge` function here, as it needs to be created from the original aggregate function with given input types.
@@ -118,6 +144,7 @@ impl StateMergeHelper {
}
/// Split an aggregate plan into two aggregate plans, one for the state function and one for the merge function.
///
pub fn split_aggr_node(aggr_plan: Aggregate) -> datafusion_common::Result<StepAggrPlan> {
let aggr = {
// certain aggr func need type coercion to work correctly, so we need to analyze the plan first.
@@ -137,6 +164,15 @@ impl StateMergeHelper {
let mut lower_aggr_exprs = vec![];
let mut upper_aggr_exprs = vec![];
// group exprs for upper plan should refer to the output group expr as column from lower plan
// to avoid re-compute group exprs again.
let upper_group_exprs = aggr
.group_expr
.iter()
.map(|c| c.qualified_name())
.map(|(r, c)| Expr::Column(Column::new(r, c)))
.collect();
for aggr_expr in aggr.aggr_expr.iter() {
let Some(aggr_func) = get_aggr_func(aggr_expr) else {
return Err(datafusion_common::DataFusionError::NotImplemented(format!(
@@ -164,6 +200,7 @@ impl StateMergeHelper {
lower_aggr_exprs.push(expr);
// then create the merge function using the physical expression of the original aggregate function
let (original_phy_expr, _filter, _ordering) = create_aggregate_expr_and_maybe_filter(
aggr_expr,
aggr.input.schema(),
@@ -179,9 +216,15 @@ impl StateMergeHelper {
let arg = Expr::Column(Column::new_unqualified(lower_state_output_col_name));
let expr = AggregateFunction {
func: Arc::new(merge_func.into()),
// notice filter/order_by is not supported in the merge function, as it's not meaningful to have them in the merge phase.
// do notice this order by is only removed in the outer logical plan, the physical plan still have order by and hence
// can create correct accumulator with order by.
params: AggregateFunctionParams {
args: vec![arg],
..aggr_func.params.clone()
distinct: aggr_func.params.distinct,
filter: None,
order_by: vec![],
null_treatment: aggr_func.params.null_treatment,
},
};
@@ -198,10 +241,18 @@ impl StateMergeHelper {
// update aggregate's output schema
let lower_plan = lower_plan.recompute_schema()?;
let mut upper = aggr.clone();
// should only affect two udaf `first_value/last_value`
// which only them have meaningful order by field
let fixed_lower_plan =
FixStateUdafOrderingAnalyzer.analyze(lower_plan, &Default::default())?;
let upper = Aggregate::try_new(
Arc::new(fixed_lower_plan.clone()),
upper_group_exprs,
upper_aggr_exprs.clone(),
)?;
let aggr_plan = LogicalPlan::Aggregate(aggr);
upper.aggr_expr = upper_aggr_exprs;
upper.input = Arc::new(lower_plan.clone());
// upper schema's output schema should be the same as the original aggregate plan's output schema
let upper_check = upper;
let upper_plan = LogicalPlan::Aggregate(upper_check).recompute_schema()?;
@@ -213,7 +264,7 @@ impl StateMergeHelper {
}
Ok(StepAggrPlan {
lower_state: lower_plan,
lower_state: fixed_lower_plan,
upper_merge: upper_plan,
})
}
@@ -224,13 +275,22 @@ impl StateMergeHelper {
pub struct StateWrapper {
inner: AggregateUDF,
name: String,
/// Default to empty, might get fixed by analyzer later
ordering: Vec<FieldRef>,
/// Default to false, might get fixed by analyzer later
distinct: bool,
}
impl StateWrapper {
/// `state_index`: The index of the state in the output of the state function.
pub fn new(inner: AggregateUDF) -> datafusion_common::Result<Self> {
let name = aggr_state_func_name(inner.name());
Ok(Self { inner, name })
Ok(Self {
inner,
name,
ordering: vec![],
distinct: false,
})
}
pub fn inner(&self) -> &AggregateUDF {
@@ -244,7 +304,19 @@ impl StateWrapper {
&self,
acc_args: &datafusion_expr::function::AccumulatorArgs,
) -> datafusion_common::Result<FieldRef> {
self.inner.return_field(acc_args.schema.fields())
let input_fields = acc_args
.exprs
.iter()
.map(|e| e.return_field(acc_args.schema))
.collect::<Result<Vec<_>, _>>()?;
self.inner.return_field(&input_fields).inspect_err(|e| {
common_telemetry::error!(
"StateWrapper: {:#?}\nacc_args:{:?}\nerror:{:?}",
&self,
&acc_args,
e
);
})
}
}
@@ -268,6 +340,7 @@ impl AggregateUDFImpl for StateWrapper {
};
self.inner.accumulator(acc_args)?
};
Ok(Box::new(StateAccum::new(inner, state_type)?))
}
@@ -294,11 +367,22 @@ impl AggregateUDFImpl for StateWrapper {
name: self.inner().name(),
input_fields,
return_field: self.inner.return_field(input_fields)?,
// TODO(discord9): how to get this?, probably ok?
ordering_fields: &[],
is_distinct: false,
// those args are also needed as they are vital to construct the state fields correctly.
ordering_fields: &self.ordering,
is_distinct: self.distinct,
};
let state_fields = self.inner.state_fields(state_fields_args)?;
let state_fields = state_fields
.into_iter()
.map(|f| {
let mut f = f.as_ref().clone();
// since state can be null when no input rows, so make all fields nullable
f.set_nullable(true);
Arc::new(f)
})
.collect::<Vec<_>>();
let struct_field = DataType::Struct(state_fields.into());
Ok(struct_field)
}
@@ -363,6 +447,39 @@ impl Accumulator for StateAccum {
.iter()
.map(|s| s.to_array())
.collect::<Result<Vec<_>, _>>()?;
let array_type = array
.iter()
.map(|a| a.data_type().clone())
.collect::<Vec<_>>();
let expected_type: Vec<_> = self
.state_fields
.iter()
.map(|f| f.data_type().clone())
.collect();
if array_type != expected_type {
debug!(
"State mismatch, expected: {}, got: {} for expected fields: {:?} and given array types: {:?}",
self.state_fields.len(),
array.len(),
self.state_fields,
array_type,
);
let guess_schema = array
.iter()
.enumerate()
.map(|(index, array)| {
Field::new(
format!("col_{index}[mismatch_state]").as_str(),
array.data_type().clone(),
true,
)
})
.collect::<Fields>();
let arr = StructArray::try_new(guess_schema, array, None)?;
return Ok(ScalarValue::Struct(Arc::new(arr)));
}
let struct_array = StructArray::try_new(self.state_fields.clone(), array, None)?;
Ok(ScalarValue::Struct(Arc::new(struct_array)))
}
@@ -401,7 +518,7 @@ pub struct MergeWrapper {
merge_signature: Signature,
/// The original physical expression of the aggregate function, can't store the original aggregate function directly, as PhysicalExpr didn't implement Any
original_phy_expr: Arc<AggregateFunctionExpr>,
original_input_types: Vec<DataType>,
return_type: DataType,
}
impl MergeWrapper {
pub fn new(
@@ -412,13 +529,14 @@ impl MergeWrapper {
let name = aggr_merge_func_name(inner.name());
// the input type is actually struct type, which is the state fields of the original aggregate function.
let merge_signature = Signature::user_defined(datafusion_expr::Volatility::Immutable);
let return_type = inner.return_type(&original_input_types)?;
Ok(Self {
inner,
name,
merge_signature,
original_phy_expr,
original_input_types,
return_type,
})
}
@@ -470,8 +588,7 @@ impl AggregateUDFImpl for MergeWrapper {
/// so return fixed return type instead of using `arg_types` to determine the return type.
fn return_type(&self, _arg_types: &[DataType]) -> datafusion_common::Result<DataType> {
// The return type is the same as the original aggregate function's return type.
let ret_type = self.inner.return_type(&self.original_input_types)?;
Ok(ret_type)
Ok(self.return_type.clone())
}
fn signature(&self) -> &Signature {
&self.merge_signature
@@ -541,10 +658,11 @@ impl Accumulator for MergeAccum {
})?;
let fields = struct_arr.fields();
if fields != &self.state_fields {
return Err(datafusion_common::DataFusionError::Internal(format!(
"Expected state fields: {:?}, got: {:?}",
debug!(
"State fields mismatch, expected: {:?}, got: {:?}",
self.state_fields, fields
)));
);
// state fields mismatch might be acceptable by datafusion, continue
}
// now fields should be the same, so we can merge the batch
@@ -561,6 +679,3 @@ impl Accumulator for MergeAccum {
self.inner.state()
}
}
#[cfg(test)]
mod tests;

View File

@@ -0,0 +1,189 @@
// Copyright 2023 Greptime Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::sync::Arc;
use common_telemetry::debug;
use datafusion::config::ConfigOptions;
use datafusion::optimizer::AnalyzerRule;
use datafusion_common::tree_node::{Transformed, TreeNode, TreeNodeRewriter};
use datafusion_expr::{AggregateUDF, Expr, ExprSchemable, LogicalPlan};
use crate::aggrs::aggr_wrapper::StateWrapper;
/// Traverse the plan, found all `__<aggr_name>_state` and fix their ordering fields
/// if their input aggr is with order by, this is currently only useful for `first_value` and `last_value` udaf
///
/// should be applied to datanode's query engine
/// TODO(discord9): proper way to extend substrait's serde ability to allow carry more info for custom udaf with more info
#[derive(Debug, Default)]
pub struct FixStateUdafOrderingAnalyzer;
impl AnalyzerRule for FixStateUdafOrderingAnalyzer {
fn name(&self) -> &str {
"FixStateUdafOrderingAnalyzer"
}
fn analyze(
&self,
plan: LogicalPlan,
_config: &ConfigOptions,
) -> datafusion_common::Result<LogicalPlan> {
plan.rewrite_with_subqueries(&mut FixOrderingRewriter::new(true))
.map(|t| t.data)
}
}
/// Traverse the plan, found all `__<aggr_name>_state` and remove their ordering fields
/// this is currently only useful for `first_value` and `last_value` udaf when need to encode to substrait
///
#[derive(Debug, Default)]
pub struct UnFixStateUdafOrderingAnalyzer;
impl AnalyzerRule for UnFixStateUdafOrderingAnalyzer {
fn name(&self) -> &str {
"UnFixStateUdafOrderingAnalyzer"
}
fn analyze(
&self,
plan: LogicalPlan,
_config: &ConfigOptions,
) -> datafusion_common::Result<LogicalPlan> {
plan.rewrite_with_subqueries(&mut FixOrderingRewriter::new(false))
.map(|t| t.data)
}
}
struct FixOrderingRewriter {
/// once fixed, mark dirty, and always recompute schema from bottom up
is_dirty: bool,
/// if true, will add the ordering field from outer aggr expr
/// if false, will remove the ordering field
is_fix: bool,
}
impl FixOrderingRewriter {
pub fn new(is_fix: bool) -> Self {
Self {
is_dirty: false,
is_fix,
}
}
}
impl TreeNodeRewriter for FixOrderingRewriter {
type Node = LogicalPlan;
/// found all `__<aggr_name>_state` and fix their ordering fields
/// if their input aggr is with order by
fn f_up(
&mut self,
node: Self::Node,
) -> datafusion_common::Result<datafusion_common::tree_node::Transformed<Self::Node>> {
let LogicalPlan::Aggregate(mut aggregate) = node else {
return if self.is_dirty {
let node = node.recompute_schema()?;
Ok(Transformed::yes(node))
} else {
Ok(Transformed::no(node))
};
};
// regex to match state udaf name
for aggr_expr in &mut aggregate.aggr_expr {
let new_aggr_expr = aggr_expr
.clone()
.transform_up(|expr| rewrite_expr(expr, &aggregate.input, self.is_fix))?;
if new_aggr_expr.transformed {
*aggr_expr = new_aggr_expr.data;
self.is_dirty = true;
}
}
if self.is_dirty {
let node = LogicalPlan::Aggregate(aggregate).recompute_schema()?;
debug!(
"FixStateUdafOrderingAnalyzer: plan schema's field changed to {:?}",
node.schema().fields()
);
Ok(Transformed::yes(node))
} else {
Ok(Transformed::no(LogicalPlan::Aggregate(aggregate)))
}
}
}
/// first see the aggr node in expr
/// as it could be nested aggr like alias(aggr(sort))
/// if contained aggr expr have a order by, and the aggr name match the regex
/// then we need to fix the ordering field of the state udaf
/// to be the same as the aggr expr
fn rewrite_expr(
expr: Expr,
aggregate_input: &Arc<LogicalPlan>,
is_fix: bool,
) -> Result<Transformed<Expr>, datafusion_common::DataFusionError> {
let Expr::AggregateFunction(aggregate_function) = expr else {
return Ok(Transformed::no(expr));
};
let Some(old_state_wrapper) = aggregate_function
.func
.inner()
.as_any()
.downcast_ref::<StateWrapper>()
else {
return Ok(Transformed::no(Expr::AggregateFunction(aggregate_function)));
};
let mut state_wrapper = old_state_wrapper.clone();
if is_fix {
// then always fix the ordering field&distinct flag and more
let order_by = aggregate_function.params.order_by.clone();
let ordering_fields: Vec<_> = order_by
.iter()
.map(|sort_expr| {
sort_expr
.expr
.to_field(&aggregate_input.schema())
.map(|(_, f)| f)
})
.collect::<datafusion_common::Result<Vec<_>>>()?;
let distinct = aggregate_function.params.distinct;
// fixing up
state_wrapper.ordering = ordering_fields;
state_wrapper.distinct = distinct;
} else {
// remove the ordering field & distinct flag
state_wrapper.ordering = vec![];
state_wrapper.distinct = false;
}
debug!(
"FixStateUdafOrderingAnalyzer: fix state udaf from {old_state_wrapper:?} to {:?}",
state_wrapper
);
let mut aggregate_function = aggregate_function;
aggregate_function.func = Arc::new(AggregateUDF::new_from_impl(state_wrapper));
Ok(Transformed::yes(Expr::AggregateFunction(
aggregate_function,
)))
}

View File

@@ -17,13 +17,15 @@ use std::pin::Pin;
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll};
use arrow::array::{ArrayRef, Float64Array, Int64Array, UInt64Array};
use arrow::array::{ArrayRef, BooleanArray, Float64Array, Int64Array, UInt64Array};
use arrow::record_batch::RecordBatch;
use arrow_schema::SchemaRef;
use common_telemetry::init_default_ut_logging;
use datafusion::catalog::{Session, TableProvider};
use datafusion::datasource::DefaultTableSource;
use datafusion::execution::{RecordBatchStream, SendableRecordBatchStream, TaskContext};
use datafusion::functions_aggregate::average::avg_udaf;
use datafusion::functions_aggregate::count::count_udaf;
use datafusion::functions_aggregate::sum::sum_udaf;
use datafusion::optimizer::analyzer::type_coercion::TypeCoercion;
use datafusion::optimizer::AnalyzerRule;
@@ -537,6 +539,208 @@ async fn test_avg_udaf() {
assert_eq!(merge_eval_res, ScalarValue::Float64(Some(132. / 45_f64)));
}
#[tokio::test]
async fn test_last_value_order_by_udaf() {
init_default_ut_logging();
let ctx = SessionContext::new();
let last_value = datafusion::functions_aggregate::first_last::last_value_udaf();
let last_value = (*last_value).clone();
let original_aggr = Aggregate::try_new(
Arc::new(dummy_table_scan()),
vec![],
vec![Expr::AggregateFunction(AggregateFunction::new_udf(
Arc::new(last_value.clone()),
vec![Expr::Column(Column::new_unqualified("number"))],
false,
None,
vec![datafusion_expr::expr::Sort::new(
Expr::Column(Column::new_unqualified("number")),
true,
true,
)],
None,
))],
)
.unwrap();
let res = StateMergeHelper::split_aggr_node(original_aggr).unwrap();
let state_func: Arc<AggregateUDF> =
Arc::new(StateWrapper::new(last_value.clone()).unwrap().into());
let expected_aggr_state_plan = LogicalPlan::Aggregate(
Aggregate::try_new(
Arc::new(dummy_table_scan()),
vec![],
vec![Expr::AggregateFunction(AggregateFunction::new_udf(
state_func,
vec![Expr::Column(Column::new_unqualified("number"))],
false,
None,
vec![datafusion_expr::expr::Sort::new(
Expr::Column(Column::new_unqualified("number")),
true,
true,
)],
None,
))],
)
.unwrap(),
);
// fix the ordering & distinct info of the state udaf, as they are not set in the wrapper.
let fixed_aggr_state_plan = FixStateUdafOrderingAnalyzer {}
.analyze(expected_aggr_state_plan.clone(), &Default::default())
.unwrap();
assert_eq!(&res.lower_state, &fixed_aggr_state_plan);
// schema is the state fields of the last_value udaf
assert_eq!(
res.lower_state.schema().as_arrow(),
&arrow_schema::Schema::new(vec![Field::new(
"__last_value_state(number) ORDER BY [number ASC NULLS FIRST]",
DataType::Struct(
vec![
Field::new("last_value[last_value]", DataType::Int64, true),
Field::new("number", DataType::Int64, true), // ordering field is added to state fields too
Field::new("is_set", DataType::Boolean, true)
]
.into()
),
true,
)])
);
let expected_merge_fn = MergeWrapper::new(
last_value.clone(),
Arc::new(
AggregateExprBuilder::new(
Arc::new(last_value.clone()),
vec![Arc::new(
datafusion::physical_expr::expressions::Column::new("number", 0),
)],
)
.schema(Arc::new(dummy_table_scan().schema().as_arrow().clone()))
.alias("last_value(number) ORDER BY [number ASC NULLS FIRST]")
.build()
.unwrap(),
),
vec![DataType::Int64],
)
.unwrap();
let expected_merge_plan = LogicalPlan::Aggregate(
Aggregate::try_new(
Arc::new(fixed_aggr_state_plan.clone()),
vec![],
vec![Expr::AggregateFunction(AggregateFunction::new_udf(
Arc::new(expected_merge_fn.into()),
vec![Expr::Column(Column::new_unqualified(
"__last_value_state(number) ORDER BY [number ASC NULLS FIRST]",
))],
false,
None,
vec![],
None,
))
.alias("last_value(number) ORDER BY [number ASC NULLS FIRST]")],
)
.unwrap(),
);
assert_eq!(&res.upper_merge, &expected_merge_plan);
let phy_aggr_state_plan = DefaultPhysicalPlanner::default()
.create_physical_plan(&fixed_aggr_state_plan, &ctx.state())
.await
.unwrap();
let aggr_exec = phy_aggr_state_plan
.as_any()
.downcast_ref::<AggregateExec>()
.unwrap();
let aggr_func_expr = &aggr_exec.aggr_expr()[0];
let mut state_accum = aggr_func_expr.create_accumulator().unwrap();
// evaluate the state function
let input = Int64Array::from(vec![Some(1), Some(2), None, Some(3)]);
let values = vec![Arc::new(input) as arrow::array::ArrayRef];
state_accum.update_batch(&values).unwrap();
let state = state_accum.state().unwrap();
// FIXME(discord9): once datafusion fixes the issue that last_value udaf state fields are not correctly(missing ordering field if `last` field is part of ordering field)
// then change it back to 3 fields
assert_eq!(state.len(), 2); // last value weird optimization(or maybe bug?) that it only has 2 state fields now
assert_eq!(state[0], ScalarValue::Int64(Some(3)));
assert_eq!(state[1], ScalarValue::Boolean(Some(true)));
let eval_res = state_accum.evaluate().unwrap();
let expected = Arc::new(
StructArray::try_new(
vec![
Field::new("col_0[mismatch_state]", DataType::Int64, true),
Field::new("col_1[mismatch_state]", DataType::Boolean, true),
// Field::new("last_value[last_value]", DataType::Int64, true),
// Field::new("number", DataType::Int64, true),
// Field::new("is_set", DataType::Boolean, true),
]
.into(),
vec![
Arc::new(Int64Array::from(vec![Some(3)])),
// Arc::new(Int64Array::from(vec![Some(3)])),
Arc::new(BooleanArray::from(vec![Some(true)])),
],
None,
)
.unwrap(),
);
assert_eq!(eval_res, ScalarValue::Struct(expected));
let phy_aggr_merge_plan = DefaultPhysicalPlanner::default()
.create_physical_plan(&res.upper_merge, &ctx.state())
.await
.unwrap();
let aggr_exec = phy_aggr_merge_plan
.as_any()
.downcast_ref::<AggregateExec>()
.unwrap();
let aggr_func_expr = &aggr_exec.aggr_expr()[0];
let mut merge_accum = aggr_func_expr.create_accumulator().unwrap();
let merge_input = vec![
Arc::new(Int64Array::from(vec![Some(3), Some(4)])) as arrow::array::ArrayRef,
Arc::new(Int64Array::from(vec![Some(3), Some(4)])),
Arc::new(BooleanArray::from(vec![Some(true), Some(true)])),
];
let merge_input_struct_arr = StructArray::try_new(
vec![
Field::new("last_value[last_value]", DataType::Int64, true),
Field::new("number", DataType::Int64, true),
Field::new("is_set", DataType::Boolean, true),
]
.into(),
merge_input,
None,
)
.unwrap();
merge_accum
.update_batch(&[Arc::new(merge_input_struct_arr)])
.unwrap();
let merge_state = merge_accum.state().unwrap();
assert_eq!(merge_state.len(), 3);
assert_eq!(merge_state[0], ScalarValue::Int64(Some(4)));
assert_eq!(merge_state[1], ScalarValue::Int64(Some(4)));
assert_eq!(merge_state[2], ScalarValue::Boolean(Some(true)));
let merge_eval_res = merge_accum.evaluate().unwrap();
// the merge function returns the last value, which is 4
assert_eq!(merge_eval_res, ScalarValue::Int64(Some(4)));
}
/// For testing whether the UDAF state fields are correctly implemented.
/// esp. for our own custom UDAF's state fields.
/// By compare eval results before and after split to state/merge functions.
@@ -548,6 +752,7 @@ async fn test_udaf_correct_eval_result() {
input_schema: SchemaRef,
input: Vec<ArrayRef>,
expected_output: Option<ScalarValue>,
// extra check function on the final array result
expected_fn: Option<ExpectedFn>,
distinct: bool,
filter: Option<Box<Expr>>,
@@ -578,6 +783,27 @@ async fn test_udaf_correct_eval_result() {
order_by: vec![],
null_treatment: None,
},
TestCase {
func: count_udaf(),
input_schema: Arc::new(arrow_schema::Schema::new(vec![Field::new(
"str_val",
DataType::Utf8,
true,
)])),
args: vec![Expr::Column(Column::new_unqualified("str_val"))],
input: vec![Arc::new(StringArray::from(vec![
Some("hello"),
Some("world"),
None,
Some("what"),
]))],
expected_output: Some(ScalarValue::Int64(Some(3))),
expected_fn: None,
distinct: false,
filter: None,
order_by: vec![],
null_treatment: None,
},
TestCase {
func: avg_udaf(),
input_schema: Arc::new(arrow_schema::Schema::new(vec![Field::new(

View File

@@ -280,6 +280,8 @@ fn build_struct(
&self,
args: datafusion::logical_expr::ScalarFunctionArgs,
) -> datafusion_common::Result<datafusion_expr::ColumnarValue> {
use common_error::ext::ErrorExt;
let columns = args.args
.iter()
.map(|arg| {
@@ -293,7 +295,7 @@ fn build_struct(
})
})
.collect::<common_query::error::Result<Vec<_>>>()
.map_err(|e| datafusion_common::DataFusionError::Execution(format!("Column conversion error: {}", e)))?;
.map_err(|e| datafusion_common::DataFusionError::Execution(format!("Column conversion error: {}", e.output_msg())))?;
// Safety check: Ensure under the `greptime` catalog for security
#user_path::ensure_greptime!(self.func_ctx);
@@ -314,14 +316,14 @@ fn build_struct(
.#handler
.as_ref()
.context(#snafu_type)
.map_err(|e| datafusion_common::DataFusionError::Execution(format!("Handler error: {}", e)))?;
.map_err(|e| datafusion_common::DataFusionError::Execution(format!("Handler error: {}", e.output_msg())))?;
let mut builder = store_api::storage::ConcreteDataType::#ret()
.create_mutable_vector(rows_num);
if columns_num == 0 {
let result = #fn_name(handler, query_ctx, &[]).await
.map_err(|e| datafusion_common::DataFusionError::Execution(format!("Function execution error: {}", e)))?;
.map_err(|e| datafusion_common::DataFusionError::Execution(format!("Function execution error: {}", e.output_msg())))?;
builder.push_value_ref(result.as_value_ref());
} else {
@@ -331,7 +333,7 @@ fn build_struct(
.collect();
let result = #fn_name(handler, query_ctx, &args).await
.map_err(|e| datafusion_common::DataFusionError::Execution(format!("Function execution error: {}", e)))?;
.map_err(|e| datafusion_common::DataFusionError::Execution(format!("Function execution error: {}", e.output_msg())))?;
builder.push_value_ref(result.as_value_ref());
}

View File

@@ -11,6 +11,7 @@ workspace = true
async-trait.workspace = true
bytes.workspace = true
common-error.workspace = true
common-function.workspace = true
common-macro.workspace = true
common-telemetry.workspace = true
datafusion.workspace = true

View File

@@ -16,9 +16,13 @@ use std::sync::Arc;
use async_trait::async_trait;
use bytes::{Buf, Bytes, BytesMut};
use common_function::aggrs::aggr_wrapper::fix_order::{
FixStateUdafOrderingAnalyzer, UnFixStateUdafOrderingAnalyzer,
};
use datafusion::execution::context::SessionState;
use datafusion::execution::runtime_env::RuntimeEnv;
use datafusion::execution::SessionStateBuilder;
use datafusion::optimizer::AnalyzerRule;
use datafusion::prelude::SessionConfig;
use datafusion_expr::LogicalPlan;
use datafusion_substrait::logical_plan::consumer::from_substrait_plan;
@@ -47,6 +51,9 @@ impl SubstraitPlan for DFLogicalSubstraitConvertor {
let df_plan = from_substrait_plan(&state, &plan)
.await
.context(DecodeDfPlanSnafu)?;
let df_plan = FixStateUdafOrderingAnalyzer {}
.analyze(df_plan, state.config_options())
.context(DecodeDfPlanSnafu)?;
Ok(df_plan)
}
@@ -55,8 +62,11 @@ impl SubstraitPlan for DFLogicalSubstraitConvertor {
plan: &Self::Plan,
serializer: impl SerializerRegistry + 'static,
) -> Result<Bytes, Self::Error> {
let plan = UnFixStateUdafOrderingAnalyzer {}
.analyze(plan.clone(), &Default::default())
.context(EncodeDfPlanSnafu)?;
let mut buf = BytesMut::new();
let substrait_plan = self.to_sub_plan(plan, serializer)?;
let substrait_plan = self.to_sub_plan(&plan, serializer)?;
substrait_plan.encode(&mut buf).context(EncodeRelSnafu)?;
Ok(buf.freeze())

View File

@@ -784,6 +784,10 @@ impl Metasrv {
&self.plugins
}
pub fn started(&self) -> Arc<AtomicBool> {
self.started.clone()
}
#[inline]
pub fn new_ctx(&self) -> Context {
let server_addr = self.options().grpc.server_addr.clone();

View File

@@ -605,7 +605,13 @@ impl RangeManipulateStream {
// shorten the range to calculate
let first_ts = ts_column.value(0);
let first_ts_aligned = (first_ts / self.interval) * self.interval;
// Preserve the query's alignment pattern when optimizing start time
let remainder = (first_ts - self.start).rem_euclid(self.interval);
let first_ts_aligned = if remainder == 0 {
first_ts
} else {
first_ts + (self.interval - remainder)
};
let last_ts = ts_column.value(ts_column.len() - 1);
let last_ts_aligned = ((last_ts + self.range) / self.interval) * self.interval;
let start = self.start.max(first_ts_aligned);
@@ -671,6 +677,7 @@ mod test {
use datafusion::datasource::source::DataSourceExec;
use datafusion::physical_expr::Partitioning;
use datafusion::physical_plan::execution_plan::{Boundedness, EmissionType};
use datafusion::physical_plan::memory::MemoryStream;
use datafusion::prelude::SessionContext;
use datatypes::arrow::array::TimestampMillisecondArray;
@@ -832,4 +839,66 @@ mod test {
}");
do_normalize_test(1, 10_001, 3_000, 1_000, expected).await;
}
#[test]
fn test_calculate_range_preserves_alignment() {
// Test case: query starts at timestamp ending in 4000, step is 30s
// Data starts at different alignment - should preserve query's 4000 pattern
let schema = Arc::new(Schema::new(vec![Field::new(
"timestamp",
TimestampMillisecondType::DATA_TYPE,
false,
)]));
let empty_stream = MemoryStream::try_new(vec![], schema.clone(), None).unwrap();
let stream = RangeManipulateStream {
start: 1758093274000, // ends in 4000
end: 1758093334000, // ends in 4000
interval: 30000, // 30s step
range: 60000, // 60s lookback
time_index: 0,
field_columns: vec![],
aligned_ts_array: Arc::new(TimestampMillisecondArray::from(vec![0i64; 0])),
output_schema: schema.clone(),
input: Box::pin(empty_stream),
metric: BaselineMetrics::new(&ExecutionPlanMetricsSet::new(), 0),
num_series: Count::new(),
};
// Create test data with timestamps not aligned to query pattern
let test_timestamps = vec![
1758093260000, // ends in 0000 (different alignment)
1758093290000, // ends in 0000
1758093320000, // ends in 0000
];
let ts_array = TimestampMillisecondArray::from(test_timestamps);
let test_schema = Arc::new(Schema::new(vec![Field::new(
"timestamp",
TimestampMillisecondType::DATA_TYPE,
false,
)]));
let batch = RecordBatch::try_new(test_schema, vec![Arc::new(ts_array)]).unwrap();
let (ranges, (start, end)) = stream.calculate_range(&batch).unwrap();
// Verify the optimized start preserves query alignment (should end in 4000)
assert_eq!(
start % 30000,
1758093274000 % 30000,
"Optimized start should preserve query alignment pattern"
);
// Verify we generate correct number of ranges for the alignment
let expected_timestamps: Vec<i64> = (start..=end).step_by(30000).collect();
assert_eq!(ranges.len(), expected_timestamps.len());
// Verify all generated timestamps maintain the same alignment pattern
for ts in expected_timestamps {
assert_eq!(
ts % 30000,
1758093274000 % 30000,
"All timestamps should maintain query alignment pattern"
);
}
}
}

View File

@@ -50,6 +50,9 @@ mod utils;
pub(crate) use utils::AliasMapping;
/// Placeholder for other physical partition columns that are not in logical table
const OTHER_PHY_PART_COL_PLACEHOLDER: &str = "__OTHER_PHYSICAL_PART_COLS_PLACEHOLDER__";
#[derive(Debug, Clone)]
pub struct DistPlannerOptions {
pub allow_query_fallback: bool,
@@ -289,7 +292,7 @@ impl PlanRewriter {
}
/// Return true if should stop and expand. The input plan is the parent node of current node
fn should_expand(&mut self, plan: &LogicalPlan) -> bool {
fn should_expand(&mut self, plan: &LogicalPlan) -> DfResult<bool> {
debug!(
"Check should_expand at level: {} with Stack:\n{}, ",
self.level,
@@ -299,20 +302,21 @@ impl PlanRewriter {
.collect::<Vec<String>>()
.join("\n"),
);
if DFLogicalSubstraitConvertor
.encode(plan, DefaultSerializer)
.is_err()
{
return true;
if let Err(e) = DFLogicalSubstraitConvertor.encode(plan, DefaultSerializer) {
debug!(
"PlanRewriter: plan cannot be converted to substrait with error={e:?}, expanding now: {plan}"
);
return Ok(true);
}
if self.expand_on_next_call {
self.expand_on_next_call = false;
return true;
debug!("PlanRewriter: expand_on_next_call is true, expanding now");
return Ok(true);
}
if self.expand_on_next_part_cond_trans_commutative {
let comm = Categorizer::check_plan(plan, self.partition_cols.clone());
let comm = Categorizer::check_plan(plan, self.partition_cols.clone())?;
match comm {
Commutativity::PartialCommutative => {
// a small difference is that for partial commutative, we still need to
@@ -328,13 +332,16 @@ impl PlanRewriter {
// again a new node that can be push down, we should just
// do push down now and avoid further expansion
self.expand_on_next_part_cond_trans_commutative = false;
return true;
debug!(
"PlanRewriter: meet a new conditional/transformed commutative plan, expanding now: {plan}"
);
return Ok(true);
}
_ => (),
}
}
match Categorizer::check_plan(plan, self.partition_cols.clone()) {
match Categorizer::check_plan(plan, self.partition_cols.clone())? {
Commutativity::Commutative => {}
Commutativity::PartialCommutative => {
if let Some(plan) = partial_commutative_transformer(plan) {
@@ -355,9 +362,8 @@ impl PlanRewriter {
}
}
Commutativity::TransformedCommutative { transformer } => {
if let Some(transformer) = transformer
&& let Some(transformer_actions) = transformer(plan)
{
if let Some(transformer) = transformer {
let transformer_actions = transformer(plan)?;
debug!(
"PlanRewriter: transformed plan: {}\n from {plan}",
transformer_actions
@@ -388,11 +394,12 @@ impl PlanRewriter {
Commutativity::NonCommutative
| Commutativity::Unimplemented
| Commutativity::Unsupported => {
return true;
debug!("PlanRewriter: meet a non-commutative plan, expanding now: {plan}");
return Ok(true);
}
}
false
Ok(false)
}
/// Update the column requirements for the current plan, plan_level is the level of the plan
@@ -489,13 +496,16 @@ impl PlanRewriter {
// as subset of phy part cols can still be used for certain optimization, and it works as if
// those columns are always null
// This helps with distinguishing between non-partitioned table and partitioned table with all phy part cols not in logical table
partition_cols
.push("__OTHER_PHYSICAL_PART_COLS_PLACEHOLDER__".to_string());
partition_cols.push(OTHER_PHY_PART_COL_PLACEHOLDER.to_string());
}
self.partition_cols = Some(
partition_cols
.into_iter()
.map(|c| {
if c == OTHER_PHY_PART_COL_PLACEHOLDER {
// for placeholder, just return a empty alias
return Ok((c.clone(), BTreeSet::new()));
}
let index =
plan.schema().index_of_column_by_name(None, &c).ok_or_else(|| {
datafusion_common::DataFusionError::Internal(
@@ -804,8 +814,7 @@ impl TreeNodeRewriter for PlanRewriter {
let parent = parent.clone();
// TODO(ruihang): avoid this clone
if self.should_expand(&parent) {
if self.should_expand(&parent)? {
// TODO(ruihang): does this work for nodes with multiple children?;
debug!(
"PlanRewriter: should expand child:\n {node}\n Of Parent: {}",

View File

@@ -27,7 +27,7 @@ use datafusion_expr::LogicalPlan;
use table::metadata::TableType;
use table::table::adapter::DfTableProviderAdapter;
use crate::dist_plan::analyzer::AliasMapping;
use crate::dist_plan::analyzer::{AliasMapping, OTHER_PHY_PART_COL_PLACEHOLDER};
use crate::dist_plan::MergeScanLogicalPlan;
/// FallbackPlanRewriter is a plan rewriter that will only push down table scan node
@@ -70,6 +70,10 @@ impl TreeNodeRewriter for FallbackPlanRewriter {
Some(partition_cols
.into_iter()
.map(|c| {
if c == OTHER_PHY_PART_COL_PLACEHOLDER {
// for placeholder, just return a empty alias
return Ok((c.clone(), BTreeSet::new()));
}
let index =
plan.schema().index_of_column_by_name(None, &c).ok_or_else(|| {
datafusion_common::DataFusionError::Internal(

View File

@@ -15,17 +15,23 @@
use std::pin::Pin;
use std::sync::Arc;
use arrow::datatypes::IntervalDayTime;
use common_catalog::consts::{DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME};
use common_error::ext::BoxedError;
use common_function::aggrs::aggr_wrapper::{StateMergeHelper, StateWrapper};
use common_recordbatch::adapter::RecordBatchMetrics;
use common_recordbatch::error::Result as RecordBatchResult;
use common_recordbatch::{OrderOption, RecordBatch, RecordBatchStream, SendableRecordBatchStream};
use common_telemetry::init_default_ut_logging;
use datafusion::datasource::DefaultTableSource;
use datafusion::execution::SessionState;
use datafusion::functions_aggregate::expr_fn::avg;
use datafusion::functions_aggregate::min_max::{max, min};
use datafusion::prelude::SessionContext;
use datafusion_common::JoinType;
use datafusion_expr::{col, lit, Expr, LogicalPlanBuilder};
use datafusion_expr::expr::ScalarFunction;
use datafusion_expr::{col, lit, AggregateUDF, Expr, LogicalPlanBuilder};
use datafusion_functions::datetime::date_bin;
use datafusion_sql::TableReference;
use datatypes::data_type::ConcreteDataType;
use datatypes::schema::{ColumnSchema, SchemaBuilder, SchemaRef};
@@ -152,6 +158,25 @@ impl Stream for EmptyStream {
}
}
fn try_encode_decode_substrait(plan: &LogicalPlan, state: SessionState) {
let sub_plan_bytes = substrait::DFLogicalSubstraitConvertor
.encode(plan, crate::query_engine::DefaultSerializer)
.unwrap();
let inner = sub_plan_bytes.clone();
let decoded_plan = futures::executor::block_on(async move {
substrait::DFLogicalSubstraitConvertor
.decode(inner, state)
.await
}).inspect_err(|e|{
use prost::Message;
let sub_plan = substrait::substrait_proto_df::proto::Plan::decode(sub_plan_bytes).unwrap();
common_telemetry::error!("Failed to decode substrait plan: {e},substrait plan: {sub_plan:#?}\nlogical plan: {plan:#?}");
})
.unwrap();
assert_eq!(*plan, decoded_plan);
}
#[test]
fn expand_proj_sort_proj() {
// use logging for better debugging
@@ -1453,3 +1478,154 @@ fn transform_sort_subquery_alias() {
.join("\n");
assert_eq!(expected, result.to_string());
}
#[test]
fn date_bin_ts_group_by() {
init_default_ut_logging();
let test_table = TestTable::table_with_name(0, "t".to_string());
let table_source = Arc::new(DefaultTableSource::new(Arc::new(
DfTableProviderAdapter::new(test_table),
)));
let date_bin_call = Expr::ScalarFunction(ScalarFunction::new_udf(
date_bin(),
vec![
lit(datafusion_common::ScalarValue::IntervalDayTime(Some(
IntervalDayTime::new(0, 60 * 1000), // 1 minute in millis
))),
col("ts"),
],
));
let plan = LogicalPlanBuilder::scan_with_filters("t", table_source, None, vec![])
.unwrap()
.aggregate(vec![date_bin_call], vec![min(col("number"))])
.unwrap()
.build()
.unwrap();
let config = ConfigOptions::default();
let result = DistPlannerAnalyzer {}.analyze(plan, &config).unwrap();
let expected = [
r#"Projection: date_bin(IntervalDayTime("IntervalDayTime { days: 0, milliseconds: 60000 }"),t.ts), min(t.number)"#,
r#" Aggregate: groupBy=[[date_bin(IntervalDayTime("IntervalDayTime { days: 0, milliseconds: 60000 }"),t.ts)]], aggr=[[__min_merge(__min_state(t.number)) AS min(t.number)]]"#,
" MergeScan [is_placeholder=false, remote_input=[",
r#"Aggregate: groupBy=[[date_bin(IntervalDayTime("IntervalDayTime { days: 0, milliseconds: 60000 }"), t.ts)]], aggr=[[__min_state(t.number)]]"#,
" TableScan: t",
"]]",
]
.join("\n");
assert_eq!(expected, result.to_string());
}
#[test]
fn test_last_value_order_by() {
init_default_ut_logging();
let test_table = TestTable::table_with_name(0, "t".to_string());
let table_provider = Arc::new(DfTableProviderAdapter::new(test_table));
let table_source = Arc::new(DefaultTableSource::new(table_provider.clone() as _));
let ctx = SessionContext::new();
ctx.register_table(TableReference::bare("t"), table_provider.clone() as _)
.unwrap();
ctx.register_udaf(AggregateUDF::new_from_impl(
StateWrapper::new(
datafusion::functions_aggregate::first_last::last_value_udaf()
.as_ref()
.clone(),
)
.unwrap(),
));
let plan = LogicalPlanBuilder::scan_with_filters("t", table_source.clone(), None, vec![])
.unwrap()
.aggregate(
Vec::<Expr>::new(),
vec![datafusion::functions_aggregate::first_last::last_value(
col("ts"),
vec![col("ts").sort(true, true)],
)],
)
.unwrap()
.build()
.unwrap();
try_encode_decode_substrait(&plan, ctx.state());
let config = ConfigOptions::default();
let result = DistPlannerAnalyzer {}
.analyze(plan.clone(), &config)
.unwrap();
let expected = [
"Projection: last_value(t.ts) ORDER BY [t.ts ASC NULLS FIRST]",
" Aggregate: groupBy=[[]], aggr=[[__last_value_merge(__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS FIRST]) AS last_value(t.ts) ORDER BY [t.ts ASC NULLS FIRST]]]",
" MergeScan [is_placeholder=false, remote_input=[",
"Aggregate: groupBy=[[]], aggr=[[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS FIRST]]]",
" TableScan: t",
"]]",
]
.join("\n");
assert_eq!(expected, result.to_string());
let LogicalPlan::Aggregate(aggr_plan) = plan else {
panic!("expect Aggregate plan");
};
let split = StateMergeHelper::split_aggr_node(aggr_plan).unwrap();
try_encode_decode_substrait(&split.lower_state, ctx.state());
}
/// try remove the order by to see if it still works
#[test]
fn test_last_value_no_order_by() {
init_default_ut_logging();
let test_table = TestTable::table_with_name(0, "t".to_string());
let table_provider = Arc::new(DfTableProviderAdapter::new(test_table));
let table_source = Arc::new(DefaultTableSource::new(table_provider.clone() as _));
let ctx = SessionContext::new();
ctx.register_table(TableReference::bare("t"), table_provider.clone() as _)
.unwrap();
ctx.register_udaf(AggregateUDF::new_from_impl(
StateWrapper::new(
datafusion::functions_aggregate::first_last::last_value_udaf()
.as_ref()
.clone(),
)
.unwrap(),
));
let plan = LogicalPlanBuilder::scan_with_filters("t", table_source, None, vec![])
.unwrap()
.aggregate(
Vec::<Expr>::new(),
vec![datafusion::functions_aggregate::first_last::last_value(
col("ts"),
vec![],
)],
)
.unwrap()
.build()
.unwrap();
let LogicalPlan::Aggregate(aggr_plan) = plan.clone() else {
panic!("expect Aggregate plan");
};
let split = StateMergeHelper::split_aggr_node(aggr_plan).unwrap();
try_encode_decode_substrait(&split.lower_state, ctx.state());
let config = ConfigOptions::default();
let result = DistPlannerAnalyzer {}
.analyze(plan.clone(), &config)
.unwrap();
let expected = [
"Projection: last_value(t.ts)",
" Aggregate: groupBy=[[]], aggr=[[__last_value_merge(__last_value_state(t.ts)) AS last_value(t.ts)]]",
" MergeScan [is_placeholder=false, remote_input=[",
"Aggregate: groupBy=[[]], aggr=[[__last_value_state(t.ts)]]",
" TableScan: t",
"]]",
]
.join("\n");
assert_eq!(expected, result.to_string());
}

View File

@@ -305,7 +305,7 @@ fn get_alias_layer_from_node(node: &LogicalPlan) -> DfResult<AliasLayer> {
} else {
// otherwise use the intersection of input and output
// TODO(discord9): maybe just make this case unsupported for now?
common_telemetry::warn!(
common_telemetry::debug!(
"Might be unsupported plan for alias tracking, track alias anyway: {}",
node
);

View File

@@ -15,9 +15,9 @@
use std::collections::HashSet;
use std::sync::Arc;
use common_function::aggrs::aggr_wrapper::{aggr_state_func_name, StateMergeHelper};
use common_function::function_registry::FUNCTION_REGISTRY;
use common_function::aggrs::aggr_wrapper::{is_all_aggr_exprs_steppable, StateMergeHelper};
use common_telemetry::debug;
use datafusion::error::Result as DfResult;
use datafusion_expr::{Expr, LogicalPlan, UserDefinedLogicalNode};
use promql::extension_plan::{
EmptyMetric, InstantManipulate, RangeManipulate, SeriesDivide, SeriesNormalize,
@@ -71,38 +71,6 @@ pub fn step_aggr_to_upper_aggr(
Ok(ret)
}
/// Check if the given aggregate expression is steppable.
/// As in if it can be split into multiple steps:
/// i.e. on datanode first call `state(input)` then
/// on frontend call `calc(merge(state))` to get the final result.
pub fn is_all_aggr_exprs_steppable(aggr_exprs: &[Expr]) -> bool {
aggr_exprs.iter().all(|expr| {
if let Some(aggr_func) = get_aggr_func(expr) {
if aggr_func.params.distinct {
// Distinct aggregate functions are not steppable(yet).
return false;
}
// whether the corresponding state function exists in the registry
FUNCTION_REGISTRY.is_aggr_func_exist(&aggr_state_func_name(aggr_func.func.name()))
} else {
false
}
})
}
pub fn get_aggr_func(expr: &Expr) -> Option<&datafusion_expr::expr::AggregateFunction> {
let mut expr_ref = expr;
while let Expr::Alias(alias) = expr_ref {
expr_ref = &alias.expr;
}
if let Expr::AggregateFunction(aggr_func) = expr_ref {
Some(aggr_func)
} else {
None
}
}
#[allow(dead_code)]
pub enum Commutativity {
Commutative,
@@ -121,15 +89,18 @@ pub enum Commutativity {
pub struct Categorizer {}
impl Categorizer {
pub fn check_plan(plan: &LogicalPlan, partition_cols: Option<AliasMapping>) -> Commutativity {
pub fn check_plan(
plan: &LogicalPlan,
partition_cols: Option<AliasMapping>,
) -> DfResult<Commutativity> {
let partition_cols = partition_cols.unwrap_or_default();
match plan {
let comm = match plan {
LogicalPlan::Projection(proj) => {
for expr in &proj.expr {
let commutativity = Self::check_expr(expr);
if !matches!(commutativity, Commutativity::Commutative) {
return commutativity;
return Ok(commutativity);
}
}
Commutativity::Commutative
@@ -142,24 +113,27 @@ impl Categorizer {
let matches_partition = Self::check_partition(&aggr.group_expr, &partition_cols);
if !matches_partition && is_all_steppable {
debug!("Plan is steppable: {plan}");
return Commutativity::TransformedCommutative {
return Ok(Commutativity::TransformedCommutative {
transformer: Some(Arc::new(|plan: &LogicalPlan| {
debug!("Before Step optimize: {plan}");
let ret = step_aggr_to_upper_aggr(plan);
ret.ok().map(|s| TransformerAction {
ret.inspect_err(|err| {
common_telemetry::error!("Failed to step aggregate plan: {err:?}");
})
.map(|s| TransformerAction {
extra_parent_plans: s.extra_parent_plans,
new_child_plan: s.new_child_plan,
})
})),
};
});
}
if !matches_partition {
return Commutativity::NonCommutative;
return Ok(Commutativity::NonCommutative);
}
for expr in &aggr.aggr_expr {
let commutativity = Self::check_expr(expr);
if !matches!(commutativity, Commutativity::Commutative) {
return commutativity;
return Ok(commutativity);
}
}
// all group by expressions are partition columns can push down, unless
@@ -170,7 +144,7 @@ impl Categorizer {
}
LogicalPlan::Sort(_) => {
if partition_cols.is_empty() {
return Commutativity::Commutative;
return Ok(Commutativity::Commutative);
}
// sort plan needs to consider column priority
@@ -219,7 +193,9 @@ impl Categorizer {
LogicalPlan::Ddl(_) => Commutativity::Unsupported,
LogicalPlan::Copy(_) => Commutativity::Unsupported,
LogicalPlan::RecursiveQuery(_) => Commutativity::Unsupported,
}
};
Ok(comm)
}
pub fn check_extension_plan(
@@ -334,7 +310,7 @@ impl Categorizer {
pub type Transformer = Arc<dyn Fn(&LogicalPlan) -> Option<LogicalPlan>>;
/// Returns transformer action that need to be applied
pub type StageTransformer = Arc<dyn Fn(&LogicalPlan) -> Option<TransformerAction>>;
pub type StageTransformer = Arc<dyn Fn(&LogicalPlan) -> DfResult<TransformerAction>>;
/// The Action that a transformer should take on the plan.
pub struct TransformerAction {
@@ -369,7 +345,7 @@ mod test {
fetch: None,
});
assert!(matches!(
Categorizer::check_plan(&plan, Some(Default::default())),
Categorizer::check_plan(&plan, Some(Default::default())).unwrap(),
Commutativity::Commutative
));
}

View File

@@ -16,6 +16,7 @@ use std::collections::HashSet;
use api::v1::SemanticType;
use arrow_schema::SortOptions;
use common_function::aggrs::aggr_wrapper::aggr_state_func_name;
use common_recordbatch::OrderOption;
use datafusion::datasource::DefaultTableSource;
use datafusion_common::tree_node::{Transformed, TreeNode, TreeNodeRecursion, TreeNodeVisitor};
@@ -217,7 +218,8 @@ impl TreeNodeVisitor<'_> for ScanHintVisitor {
is_all_last_value = false;
break;
};
if func.func.name() != "last_value"
if (func.func.name() != "last_value"
&& func.func.name() != aggr_state_func_name("last_value"))
|| func.params.filter.is_some()
|| func.params.distinct
{

View File

@@ -1222,12 +1222,13 @@ impl PromPlanner {
let mut exprs = Vec::with_capacity(labels.labels.len());
for label in &labels.labels {
// nonexistence label will be ignored
if let Ok(field) = input_schema.field_with_unqualified_name(label) {
exprs.push(DfExpr::Column(Column::from(field.name())));
if let Some(column_name) = Self::find_case_sensitive_column(input_schema, label)
{
exprs.push(DfExpr::Column(Column::from_name(column_name.clone())));
if update_ctx {
// update the tag columns in context
self.ctx.tag_columns.push(label.clone());
self.ctx.tag_columns.push(column_name);
}
}
}
@@ -1290,13 +1291,12 @@ impl PromPlanner {
continue;
}
let col = if table_schema
.field_with_unqualified_name(&matcher.name)
.is_err()
{
DfExpr::Literal(ScalarValue::Utf8(Some(String::new())), None).alias(matcher.name)
let column_name = Self::find_case_sensitive_column(table_schema, matcher.name.as_str());
let col = if let Some(column_name) = column_name {
DfExpr::Column(Column::from_name(column_name))
} else {
DfExpr::Column(Column::from_name(matcher.name))
DfExpr::Literal(ScalarValue::Utf8(Some(String::new())), None)
.alias(matcher.name.clone())
};
let lit = DfExpr::Literal(ScalarValue::Utf8(Some(matcher.value)), None);
let expr = match matcher.op {
@@ -1353,6 +1353,14 @@ impl PromPlanner {
Ok(exprs)
}
fn find_case_sensitive_column(schema: &DFSchemaRef, column: &str) -> Option<String> {
schema
.fields()
.iter()
.find(|field| field.name() == column)
.map(|field| field.name().clone())
}
fn table_ref(&self) -> Result<TableReference> {
let table_name = self
.ctx

View File

@@ -19,6 +19,7 @@ use std::sync::{Arc, RwLock};
use async_trait::async_trait;
use catalog::CatalogManagerRef;
use common_base::Plugins;
use common_function::aggrs::aggr_wrapper::fix_order::FixStateUdafOrderingAnalyzer;
use common_function::function_factory::ScalarFunctionFactory;
use common_function::handlers::{
FlowServiceHandlerRef, ProcedureServiceHandlerRef, TableMutationHandlerRef,
@@ -136,6 +137,8 @@ impl QueryEngineState {
analyzer.rules.push(Arc::new(DistPlannerAnalyzer));
}
analyzer.rules.push(Arc::new(FixStateUdafOrderingAnalyzer));
let mut optimizer = Optimizer::new();
optimizer.rules.push(Arc::new(ScanHintRule));

View File

@@ -1 +1 @@
v0.11.4
v0.11.6

View File

@@ -292,11 +292,18 @@ impl<'a> ParserContext<'a> {
let output_table_name = self.intern_parse_table_name()?;
let expire_after = if self
.parser
.consume_tokens(&[Token::make_keyword(EXPIRE), Token::make_keyword(AFTER)])
let expire_after = if let Token::Word(w1) = &self.parser.peek_token().token
&& w1.value.eq_ignore_ascii_case(EXPIRE)
{
Some(self.parse_interval_no_month("EXPIRE AFTER")?)
self.parser.next_token();
if let Token::Word(w2) = &self.parser.peek_token().token
&& w2.value.eq_ignore_ascii_case(AFTER)
{
self.parser.next_token();
Some(self.parse_interval_no_month("EXPIRE AFTER")?)
} else {
None
}
} else {
None
};
@@ -1500,6 +1507,45 @@ SELECT max(c1), min(c2) FROM schema_2.table_2;",
comment: None,
},
),
(
r"
create flow `task_3`
sink to schema_1.table_1
expire after '10 minutes'
as
select max(c1), min(c2) from schema_2.table_2;",
CreateFlowWoutQuery {
flow_name: ObjectName::from(vec![Ident::with_quote('`', "task_3")]),
sink_table_name: ObjectName::from(vec![
Ident::new("schema_1"),
Ident::new("table_1"),
]),
or_replace: false,
if_not_exists: false,
expire_after: Some(600), // 10 minutes in seconds
comment: None,
},
),
(
r"
create or replace flow if not exists task_4
sink to schema_1.table_1
expire after interval '2 hours'
comment 'lowercase test'
as
select max(c1), min(c2) from schema_2.table_2;",
CreateFlowWoutQuery {
flow_name: ObjectName::from(vec![Ident::new("task_4")]),
sink_table_name: ObjectName::from(vec![
Ident::new("schema_1"),
Ident::new("table_1"),
]),
or_replace: true,
if_not_exists: true,
expire_after: Some(7200), // 2 hours in seconds
comment: Some("lowercase test".to_string()),
},
),
];
for (sql, expected) in testcases {

View File

@@ -34,7 +34,6 @@ const FORMAT: &str = "FORMAT";
use sqlparser::parser::Parser;
use crate::dialect::GreptimeDbDialect;
use crate::parsers::error::{
ConvertToLogicalExpressionSnafu, EvaluationSnafu, ParserSnafu, TQLError,
};
@@ -106,36 +105,49 @@ impl ParserContext<'_> {
let (start, end, step, lookback) = match parser.peek_token().token {
Token::LParen => {
let _consume_lparen_token = parser.next_token();
let start = Self::parse_string_or_number_or_word(
parser,
&[Token::Comma],
require_now_expr,
)?
.0;
let end = Self::parse_string_or_number_or_word(
parser,
&[Token::Comma],
require_now_expr,
)?
.0;
let exprs = parser
.parse_comma_separated(Parser::parse_expr)
.context(ParserSnafu)?;
let (step, delimiter) = Self::parse_string_or_number_or_word(
parser,
&[Token::Comma, Token::RParen],
false,
let param_count = exprs.len();
if param_count != 3 && param_count != 4 {
return Err(ParserError::ParserError(
format!("Expected 3 or 4 expressions in TQL parameters (start, end, step, [lookback]), but found {}", param_count)
))
.context(ParserSnafu);
}
let mut exprs_iter = exprs.into_iter();
// Safety: safe to call next and unwrap, because we already check the param_count above.
let start = Self::parse_expr_to_literal_or_ts(
exprs_iter.next().unwrap(),
require_now_expr,
)?;
let lookback = if delimiter == Token::Comma {
Self::parse_string_or_number_or_word(parser, &[Token::RParen], false)
.ok()
.map(|t| t.0)
} else {
None
};
let end = Self::parse_expr_to_literal_or_ts(
exprs_iter.next().unwrap(),
require_now_expr,
)?;
let step = Self::parse_expr_to_literal_or_ts(exprs_iter.next().unwrap(), false)?;
let lookback = exprs_iter
.next()
.map(|expr| Self::parse_expr_to_literal_or_ts(expr, false))
.transpose()?;
if !parser.consume_token(&Token::RParen) {
return Err(ParserError::ParserError(format!(
"Expected ')' after TQL parameters, but found: {}",
parser.peek_token()
)))
.context(ParserSnafu);
}
(start, end, step, lookback)
}
_ => ("0".to_string(), "0".to_string(), "5m".to_string(), None),
};
let query = Self::parse_tql_query(parser, self.sql).context(ParserSnafu)?;
Ok(TqlParameters::new(start, end, step, lookback, query))
}
@@ -179,72 +191,43 @@ impl ParserContext<'_> {
}
}
/// Try to parse and consume a string, number or word token.
/// Return `Ok` if it's parsed and one of the given delimiter tokens is consumed.
/// The string and matched delimiter will be returned as a tuple.
fn parse_string_or_number_or_word(
parser: &mut Parser,
delimiter_tokens: &[Token],
require_now_expr: bool,
) -> std::result::Result<(String, Token), TQLError> {
let mut tokens = vec![];
while !delimiter_tokens.contains(&parser.peek_token().token) {
let token = parser.next_token().token;
if matches!(token, Token::EOF) {
break;
}
tokens.push(token);
}
let result = match tokens.len() {
0 => Err(ParserError::ParserError(
"Expected at least one token".to_string(),
))
.context(ParserSnafu),
1 => {
let value = match tokens[0].clone() {
Token::Number(n, _) if !require_now_expr => n,
Token::DoubleQuotedString(s) | Token::SingleQuotedString(s)
if !require_now_expr =>
{
s
}
Token::Word(_) => Self::parse_tokens_to_ts(tokens, require_now_expr)?,
unexpected => {
if !require_now_expr {
return Err(ParserError::ParserError(format!(
"Expected number, string or word, but have {unexpected:?}"
)))
.context(ParserSnafu);
} else {
return Err(ParserError::ParserError(format!(
"Expected expression containing `now()`, but have {unexpected:?}"
)))
.context(ParserSnafu);
}
}
};
Ok(value)
}
_ => Self::parse_tokens_to_ts(tokens, require_now_expr),
};
for token in delimiter_tokens {
if parser.consume_token(token) {
return result.map(|v| (v, token.clone()));
}
}
Err(ParserError::ParserError(format!(
"Delimiters not match {delimiter_tokens:?}"
)))
.context(ParserSnafu)
}
/// Parse the tokens to seconds and convert to string.
fn parse_tokens_to_ts(
tokens: Vec<Token>,
/// Parse the expression to a literal string or a timestamp in seconds.
fn parse_expr_to_literal_or_ts(
parser_expr: sqlparser::ast::Expr,
require_now_expr: bool,
) -> std::result::Result<String, TQLError> {
match parser_expr {
sqlparser::ast::Expr::Value(v) => match v.value {
sqlparser::ast::Value::Number(s, _) if !require_now_expr => Ok(s),
sqlparser::ast::Value::DoubleQuotedString(s)
| sqlparser::ast::Value::SingleQuotedString(s)
if !require_now_expr =>
{
Ok(s)
}
unexpected => {
if !require_now_expr {
Err(ParserError::ParserError(format!(
"Expected number, string or word, but have {unexpected:?}"
)))
.context(ParserSnafu)
} else {
Err(ParserError::ParserError(format!(
"Expected expression containing `now()`, but have {unexpected:?}"
)))
.context(ParserSnafu)
}
}
},
_ => Self::parse_expr_to_ts(parser_expr, require_now_expr),
}
}
/// Parse the expression to a timestamp in seconds.
fn parse_expr_to_ts(
parser_expr: sqlparser::ast::Expr,
require_now_expr: bool,
) -> std::result::Result<String, TQLError> {
let parser_expr = Self::parse_to_expr(tokens)?;
let lit = utils::parser_expr_to_scalar_value_literal(parser_expr, require_now_expr)
.map_err(Box::new)
.context(ConvertToLogicalExpressionSnafu)?;
@@ -267,13 +250,6 @@ impl ParserContext<'_> {
})
}
fn parse_to_expr(tokens: Vec<Token>) -> std::result::Result<sqlparser::ast::Expr, TQLError> {
Parser::new(&GreptimeDbDialect {})
.with_tokens(tokens)
.parse_expr()
.context(ParserSnafu)
}
fn parse_tql_query(parser: &mut Parser, sql: &str) -> std::result::Result<String, ParserError> {
while matches!(parser.peek_token().token, Token::Comma) {
let _skip_token = parser.next_token();
@@ -405,6 +381,60 @@ mod tests {
assert!(result.is_err());
}
#[test]
fn test_parse_tql_eval_with_date_trunc() {
let sql = "TQL EVAL (date_trunc('day', now() - interval '1' day), date_trunc('day', now()), '1h') http_requests_total{environment=~'staging|testing|development',method!='GET'} @ 1609746000 offset 5m";
let statement = parse_into_statement(sql);
match statement {
Statement::Tql(Tql::Eval(eval)) => {
// date_trunc('day', now() - interval '1' day) should resolve to start of yesterday
// date_trunc('day', now()) should resolve to start of today
// The exact values depend on when the test runs, but we can verify the structure
assert!(eval.start.parse::<i64>().is_ok());
assert!(eval.end.parse::<i64>().is_ok());
assert_eq!(eval.step, "1h");
assert_eq!(eval.lookback, None);
assert_eq!(
eval.query,
"http_requests_total{environment=~'staging|testing|development',method!='GET'} @ 1609746000 offset 5m"
);
}
_ => unreachable!(),
}
// Test with 4 parameters including lookback
let sql = "TQL EVAL (date_trunc('hour', now() - interval '6' hour), date_trunc('hour', now()), '30m', '5m') cpu_usage_total";
let statement = parse_into_statement(sql);
match statement {
Statement::Tql(Tql::Eval(eval)) => {
assert!(eval.start.parse::<i64>().is_ok());
assert!(eval.end.parse::<i64>().is_ok());
assert_eq!(eval.step, "30m");
assert_eq!(eval.lookback, Some("5m".to_string()));
assert_eq!(eval.query, "cpu_usage_total");
}
_ => unreachable!(),
}
}
#[test]
fn test_parse_tql_analyze_with_date_trunc() {
let sql = "TQL ANALYZE VERBOSE FORMAT JSON (date_trunc('week', now() - interval '2' week), date_trunc('week', now()), '4h', '1h') network_bytes_total";
let statement = parse_into_statement(sql);
match statement {
Statement::Tql(Tql::Analyze(analyze)) => {
assert!(analyze.start.parse::<i64>().is_ok());
assert!(analyze.end.parse::<i64>().is_ok());
assert_eq!(analyze.step, "4h");
assert_eq!(analyze.lookback, Some("1h".to_string()));
assert_eq!(analyze.query, "network_bytes_total");
assert!(analyze.is_verbose);
assert_eq!(analyze.format, Some(AnalyzeFormat::JSON));
}
_ => unreachable!(),
}
}
#[test]
fn test_parse_tql_eval() {
let sql = "TQL EVAL (1676887657, 1676887659, '1m') http_requests_total{environment=~'staging|testing|development',method!='GET'} @ 1609746000 offset 5m";
@@ -901,17 +931,26 @@ mod tests {
let sql = "TQL EVAL (1676887657, 1676887659, 1m) http_requests_total{environment=~'staging|testing|development',method!='GET'} @ 1609746000 offset 5m";
let result =
ParserContext::create_with_dialect(sql, dialect, parse_options.clone()).unwrap_err();
assert!(result
.output_msg()
.contains("Failed to extract a timestamp value"));
assert!(
result
.output_msg()
.contains("Expected ')' after TQL parameters, but found: m"),
"{}",
result.output_msg()
);
// missing end
let sql = "TQL EVAL (1676887657, '1m') http_requests_total{environment=~'staging|testing|development',method!='GET'} @ 1609746000 offset 5m";
let result =
ParserContext::create_with_dialect(sql, dialect, parse_options.clone()).unwrap_err();
assert!(result
.output_msg()
.contains("Failed to extract a timestamp value"));
assert!(
result
.output_msg()
.contains("Expected 3 or 4 expressions in TQL parameters"),
"{}",
result.output_msg()
);
// empty TQL query
let sql = "TQL EVAL (0, 30, '10s')";
@@ -923,6 +962,12 @@ mod tests {
let sql = "tql eval (0, 0, '1s) t;;';";
let result =
ParserContext::create_with_dialect(sql, dialect, parse_options.clone()).unwrap_err();
assert!(result.output_msg().contains("Delimiters not match"));
assert!(
result
.output_msg()
.contains("Expected ')' after TQL parameters, but found: ;"),
"{}",
result.output_msg()
);
}
}

View File

@@ -14,13 +14,17 @@ Affected Rows: 0
INSERT INTO
integers (host, i, ts)
VALUES
('220-A', 2, '2023-01-01 00:00:00'),
('220-B', 3, '2023-01-01 00:00:00'),
('550-A', 1, '2023-01-01 00:00:00'),
('550-B', 5, '2023-01-01 00:00:00'),
('550-A', 2, '2023-01-01 01:00:00'),
('550-W', 3, '2023-01-01 02:00:00'),
('550-W', 4, '2023-01-01 03:00:00');
('550-Z', 4, '2023-01-01 02:00:00'),
('550-W', 5, '2023-01-01 03:00:00'),
('550-Z', 6, '2023-01-01 03:00:00');
Affected Rows: 5
Affected Rows: 9
SELECT
count(i),
@@ -33,7 +37,7 @@ FROM
+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
| count(integers.i) | sum(integers.i) | uddsketch_calc(Float64(0.5),uddsketch_state(Int64(128),Float64(0.01),integers.i)) | hll_count(hll(integers.i)) |
+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
| 5 | 15 | 2.9742334234767016 | 5 |
| 9 | 31 | 2.9742334234767016 | 6 |
+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
-- SQLNESS REPLACE (-+) -
@@ -122,11 +126,11 @@ SELECT
FROM
integers;
+-----------------+
| avg(integers.i) |
+-----------------+
| 3.0 |
+-----------------+
+--------------------+
| avg(integers.i) |
+--------------------+
| 3.4444444444444446 |
+--------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
@@ -214,10 +218,10 @@ ORDER BY
+---------------------+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
| ts | count(integers.i) | sum(integers.i) | uddsketch_calc(Float64(0.5),uddsketch_state(Int64(128),Float64(0.01),integers.i)) | hll_count(hll(integers.i)) |
+---------------------+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
| 2023-01-01T00:00:00 | 2 | 6 | 5.002829575110705 | 2 |
| 2023-01-01T00:00:00 | 4 | 11 | 2.9742334234767016 | 4 |
| 2023-01-01T01:00:00 | 1 | 2 | 1.9936617014173446 | 1 |
| 2023-01-01T02:00:00 | 1 | 3 | 2.9742334234767016 | 1 |
| 2023-01-01T03:00:00 | 1 | 4 | 4.014835333028587 | 1 |
| 2023-01-01T02:00:00 | 2 | 7 | 4.014835333028587 | 2 |
| 2023-01-01T03:00:00 | 2 | 11 | 5.98951037117262 | 2 |
+---------------------+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
-- SQLNESS REPLACE (-+) -
@@ -321,6 +325,129 @@ ORDER BY
|_|_| Total rows: 4_|
+-+-+-+
SELECT
date_bin('2s'::INTERVAL, ts) as time_window,
count(i),
sum(i),
uddsketch_calc(0.5, uddsketch_state(128, 0.01, i)),
hll_count(hll(i))
FROM
integers
GROUP BY
time_window
ORDER BY
time_window;
+---------------------+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
| time_window | count(integers.i) | sum(integers.i) | uddsketch_calc(Float64(0.5),uddsketch_state(Int64(128),Float64(0.01),integers.i)) | hll_count(hll(integers.i)) |
+---------------------+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
| 2023-01-01T00:00:00 | 4 | 11 | 2.9742334234767016 | 4 |
| 2023-01-01T01:00:00 | 1 | 2 | 1.9936617014173446 | 1 |
| 2023-01-01T02:00:00 | 2 | 7 | 4.014835333028587 | 2 |
| 2023-01-01T03:00:00 | 2 | 11 | 5.98951037117262 | 2 |
+---------------------+-------------------+-----------------+-----------------------------------------------------------------------------------+----------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
EXPLAIN
SELECT
date_bin('2s'::INTERVAL, ts) as time_window,
count(i),
sum(i),
uddsketch_calc(0.5, uddsketch_state(128, 0.01, i)),
hll_count(hll(i))
FROM
integers
GROUP BY
time_window
ORDER BY
time_window;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST_|
|_|_Projection: date_bin(Utf8("2 seconds"),integers.ts) AS time_window, count(integers.i), sum(integers.i), uddsketch_calc(Float64(0.5), uddsketch_state(Int64(128),Float64(0.01),integers.i)), hll_count(hll(integers.i))_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("2 seconds"),integers.ts)]], aggr=[[__count_merge(__count_state(integers.i)) AS count(integers.i), __sum_merge(__sum_state(integers.i)) AS sum(integers.i), __uddsketch_state_merge(__uddsketch_state_state(Int64(128),Float64(0.01),integers.i)) AS uddsketch_state(Int64(128),Float64(0.01),integers.i), __hll_merge(__hll_state(integers.i)) AS hll(integers.i)]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("2 seconds") AS Interval(MonthDayNano)), integers.ts)]], aggr=[[__count_state(integers.i), __sum_state(integers.i), __uddsketch_state_state(Int64(128), Float64(0.01), CAST(integers.i AS Float64)), __hll_state(CAST(integers.i AS Utf8))]]_|
|_|_TableScan: integers_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@0 ASC NULLS LAST], preserve_partitioning=[true]_|
|_|_ProjectionExec: expr=[date_bin(Utf8("2 seconds"),integers.ts)@0 as time_window, count(integers.i)@1 as count(integers.i), sum(integers.i)@2 as sum(integers.i), uddsketch_calc(0.5, uddsketch_state(Int64(128),Float64(0.01),integers.i)@3) as uddsketch_calc(Float64(0.5),uddsketch_state(Int64(128),Float64(0.01),integers.i)), hll_count(hll(integers.i)@4) as hll_count(hll(integers.i))]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("2 seconds"),integers.ts)@0 as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[count(integers.i), sum(integers.i), uddsketch_state(Int64(128),Float64(0.01),integers.i), hll(integers.i)]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: partitioning=REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("2 seconds"),integers.ts)@0 as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[count(integers.i), sum(integers.i), uddsketch_state(Int64(128),Float64(0.01),integers.i), hll(integers.i)]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
EXPLAIN ANALYZE
SELECT
date_bin('2s'::INTERVAL, ts) as time_window,
count(i),
sum(i),
uddsketch_calc(0.5, uddsketch_state(128, 0.01, i)),
hll_count(hll(i))
FROM
integers
GROUP BY
time_window
ORDER BY
time_window;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@0 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_ProjectionExec: expr=[date_bin(Utf8("2 seconds"),integers.ts)@0 as time_window, count(integers.i)@1 as count(integers.i), sum(integers.i)@2 as sum(integers.i), uddsketch_calc(0.5, uddsketch_state(Int64(128),Float64(0.01),integers.i)@3) as uddsketch_calc(Float64(0.5),uddsketch_state(Int64(128),Float64(0.01),integers.i)), hll_count(hll(integers.i)@4) as hll_count(hll(integers.i))] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("2 seconds"),integers.ts)@0 as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[count(integers.i), sum(integers.i), uddsketch_state(Int64(128),Float64(0.01),integers.i), hll(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("2 seconds"),integers.ts)@0 as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[count(integers.i), sum(integers.i), uddsketch_state(Int64(128),Float64(0.01),integers.i), hll(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("2 seconds"),integers.ts)@0 as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[__count_state(integers.i), __sum_state(integers.i), __uddsketch_state_state(Int64(128),Float64(0.01),integers.i), __hll_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 2000000000 }, ts@1) as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[__count_state(integers.i), __sum_state(integers.i), __uddsketch_state_state(Int64(128),Float64(0.01),integers.i), __hll_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("2 seconds"),integers.ts)@0 as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[__count_state(integers.i), __sum_state(integers.i), __uddsketch_state_state(Int64(128),Float64(0.01),integers.i), __hll_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 2000000000 }, ts@1) as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[__count_state(integers.i), __sum_state(integers.i), __uddsketch_state_state(Int64(128),Float64(0.01),integers.i), __hll_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("2 seconds"),integers.ts)@0 as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[__count_state(integers.i), __sum_state(integers.i), __uddsketch_state_state(Int64(128),Float64(0.01),integers.i), __hll_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 2000000000 }, ts@1) as date_bin(Utf8("2 seconds"),integers.ts)], aggr=[__count_state(integers.i), __sum_state(integers.i), __uddsketch_state_state(Int64(128),Float64(0.01),integers.i), __hll_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
DROP TABLE integers;
Affected Rows: 0

View File

@@ -12,11 +12,15 @@ CREATE TABLE integers(
INSERT INTO
integers (host, i, ts)
VALUES
('220-A', 2, '2023-01-01 00:00:00'),
('220-B', 3, '2023-01-01 00:00:00'),
('550-A', 1, '2023-01-01 00:00:00'),
('550-B', 5, '2023-01-01 00:00:00'),
('550-A', 2, '2023-01-01 01:00:00'),
('550-W', 3, '2023-01-01 02:00:00'),
('550-W', 4, '2023-01-01 03:00:00');
('550-Z', 4, '2023-01-01 02:00:00'),
('550-W', 5, '2023-01-01 03:00:00'),
('550-Z', 6, '2023-01-01 03:00:00');
SELECT
count(i),
@@ -142,4 +146,60 @@ GROUP BY
ORDER BY
ts;
SELECT
date_bin('2s'::INTERVAL, ts) as time_window,
count(i),
sum(i),
uddsketch_calc(0.5, uddsketch_state(128, 0.01, i)),
hll_count(hll(i))
FROM
integers
GROUP BY
time_window
ORDER BY
time_window;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
EXPLAIN
SELECT
date_bin('2s'::INTERVAL, ts) as time_window,
count(i),
sum(i),
uddsketch_calc(0.5, uddsketch_state(128, 0.01, i)),
hll_count(hll(i))
FROM
integers
GROUP BY
time_window
ORDER BY
time_window;
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
EXPLAIN ANALYZE
SELECT
date_bin('2s'::INTERVAL, ts) as time_window,
count(i),
sum(i),
uddsketch_calc(0.5, uddsketch_state(128, 0.01, i)),
hll_count(hll(i))
FROM
integers
GROUP BY
time_window
ORDER BY
time_window;
DROP TABLE integers;

View File

@@ -1037,3 +1037,277 @@ drop table aggr_optimize_not;
Affected Rows: 0
--
-- Additional test cases for step aggregation pushdown
--
CREATE TABLE step_aggr_extended (
pk_col_1 STRING,
pk_col_2 BIGINT,
val_col_1 BIGINT,
val_col_2 STRING,
val_col_3 BIGINT,
ts TIMESTAMP TIME INDEX,
PRIMARY KEY(pk_col_1, pk_col_2)
) PARTITION ON COLUMNS (pk_col_1) (
pk_col_1 < 'f',
pk_col_1 >= 'f'
);
Affected Rows: 0
INSERT INTO step_aggr_extended VALUES
('a', 1, 100, 'v1', 10, 1672531200000),
('a', 2, 200, 'v2', NULL, 1672531201000),
('g', 1, 300, 'v1', 30, 1672531202000),
('g', 2, 400, 'v2', 40, 1672531203000),
('a', 3, 100, 'v3', 10, 1672531204000),
('g', 3, 300, 'v3', 30, 1672531205000),
('h', 4, 500, NULL, 50, 1672531206000);
Affected Rows: 7
-- Case 12: GROUP BY includes a mix of partition key and non-partition key.
-- `pk_col_1` is a partition key, `pk_col_2` is not.
-- This should pushdown entire aggregation to datanodes since it's partitioned by `pk_col_1`.
-- Expected: Full pushdown of aggregation to datanodes.
SELECT pk_col_1, pk_col_2, sum(val_col_1) FROM step_aggr_extended GROUP BY pk_col_1, pk_col_2 ORDER BY pk_col_1, pk_col_2;
+----------+----------+-----------------------------------+
| pk_col_1 | pk_col_2 | sum(step_aggr_extended.val_col_1) |
+----------+----------+-----------------------------------+
| a | 1 | 100 |
| a | 2 | 200 |
| a | 3 | 100 |
| g | 1 | 300 |
| g | 2 | 400 |
| g | 3 | 300 |
| h | 4 | 500 |
+----------+----------+-----------------------------------+
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT pk_col_1, pk_col_2, sum(val_col_1) FROM step_aggr_extended GROUP BY pk_col_1, pk_col_2 ORDER BY pk_col_1, pk_col_2;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: step_aggr_extended.pk_col_1 ASC NULLS LAST, step_aggr_extended.pk_col_2 ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: step_aggr_extended.pk_col_1 ASC NULLS LAST, step_aggr_extended.pk_col_2 ASC NULLS LAST_|
|_|_Projection: step_aggr_extended.pk_col_1, step_aggr_extended.pk_col_2, sum(step_aggr_extended.val_col_1)_|
|_|_Aggregate: groupBy=[[step_aggr_extended.pk_col_1, step_aggr_extended.pk_col_2]], aggr=[[sum(step_aggr_extended.val_col_1)]] |
|_|_TableScan: step_aggr_extended_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [pk_col_1@0 ASC NULLS LAST, pk_col_2@1 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- Case 13: COUNT(DISTINCT) aggregation.
-- `DISTINCT` aggregation is more complex and requires a two-phase distinct calculation in a distributed environment. Currently not supported for pushdown.
-- Expected: datanode only do table scan, actual aggregation happens on frontend.
SELECT COUNT(DISTINCT val_col_1) FROM step_aggr_extended;
+----------------------------------------------+
| count(DISTINCT step_aggr_extended.val_col_1) |
+----------------------------------------------+
| 5 |
+----------------------------------------------+
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT COUNT(DISTINCT val_col_1) FROM step_aggr_extended;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Projection: count(alias1) AS count(DISTINCT step_aggr_extended.val_col_1)_|
|_|_Aggregate: groupBy=[[]], aggr=[[count(alias1)]]_|
|_|_Aggregate: groupBy=[[step_aggr_extended.val_col_1 AS alias1]], aggr=[[]]_|
|_|_Projection: step_aggr_extended.val_col_1_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| TableScan: step_aggr_extended_|
|_| ]]_|
| physical_plan | ProjectionExec: expr=[count(alias1)@0 as count(DISTINCT step_aggr_extended.val_col_1)]_|
|_|_AggregateExec: mode=Final, gby=[], aggr=[count(alias1)]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[count(alias1)]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[alias1@0 as alias1], aggr=[]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: partitioning=REDACTED
|_|_AggregateExec: mode=Partial, gby=[val_col_1@0 as alias1], aggr=[]_|
|_|_ProjectionExec: expr=[val_col_1@2 as val_col_1]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- Case 14: Aggregation with a HAVING clause.
-- The `HAVING` clause filters results after aggregation.
-- Expected: The `HAVING` filter should be applied on the frontend after the final aggregation is complete, not pushed down to datanodes.
SELECT pk_col_2, sum(val_col_1) FROM step_aggr_extended GROUP BY pk_col_2 HAVING sum(val_col_1) > 300 ORDER BY pk_col_2;
+----------+-----------------------------------+
| pk_col_2 | sum(step_aggr_extended.val_col_1) |
+----------+-----------------------------------+
| 1 | 400 |
| 2 | 600 |
| 3 | 400 |
| 4 | 500 |
+----------+-----------------------------------+
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT pk_col_2, sum(val_col_1) FROM step_aggr_extended GROUP BY pk_col_2 HAVING sum(val_col_1) > 300 ORDER BY pk_col_2;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: step_aggr_extended.pk_col_2 ASC NULLS LAST_|
|_|_Filter: sum(step_aggr_extended.val_col_1) > Int64(300)_|
|_|_Aggregate: groupBy=[[step_aggr_extended.pk_col_2]], aggr=[[__sum_merge(__sum_state(step_aggr_extended.val_col_1)) AS sum(step_aggr_extended.val_col_1)]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[step_aggr_extended.pk_col_2]], aggr=[[__sum_state(step_aggr_extended.val_col_1)]]_|
|_|_TableScan: step_aggr_extended_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [pk_col_2@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[pk_col_2@0 ASC NULLS LAST], preserve_partitioning=[true]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_FilterExec: sum(step_aggr_extended.val_col_1)@1 > 300_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[pk_col_2@0 as pk_col_2], aggr=[sum(step_aggr_extended.val_col_1)]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: partitioning=REDACTED
|_|_AggregateExec: mode=Partial, gby=[pk_col_2@0 as pk_col_2], aggr=[sum(step_aggr_extended.val_col_1)]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- Case 15: Aggregation on a column with NULL values.
-- `SUM` should ignore NULLs. `COUNT(val_col_2)` should count non-nulls, `COUNT(*)` should count all rows.
-- Expected: Correct aggregation results, proving NULLs are handled properly in a distributed context.
SELECT SUM(val_col_3), COUNT(val_col_2), COUNT(val_col_3), COUNT(*) FROM step_aggr_extended;
+-----------------------------------+-------------------------------------+-------------------------------------+----------+
| sum(step_aggr_extended.val_col_3) | count(step_aggr_extended.val_col_2) | count(step_aggr_extended.val_col_3) | count(*) |
+-----------------------------------+-------------------------------------+-------------------------------------+----------+
| 170 | 6 | 6 | 7 |
+-----------------------------------+-------------------------------------+-------------------------------------+----------+
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT SUM(val_col_3), COUNT(val_col_2), COUNT(val_col_3), COUNT(*) FROM step_aggr_extended;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Projection: sum(step_aggr_extended.val_col_3), count(step_aggr_extended.val_col_2), count(step_aggr_extended.val_col_3), count(Int64(1)) AS count(*)_|
|_|_Aggregate: groupBy=[[]], aggr=[[__sum_merge(__sum_state(step_aggr_extended.val_col_3)) AS sum(step_aggr_extended.val_col_3), __count_merge(__count_state(step_aggr_extended.val_col_2)) AS count(step_aggr_extended.val_col_2), __count_merge(__count_state(step_aggr_extended.val_col_3)) AS count(step_aggr_extended.val_col_3), __count_merge(__count_state(step_aggr_extended.ts)) AS count(Int64(1))]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__sum_state(step_aggr_extended.val_col_3), __count_state(step_aggr_extended.val_col_2), __count_state(step_aggr_extended.val_col_3), __count_state(step_aggr_extended.ts)]]_|
|_|_TableScan: step_aggr_extended_|
|_| ]]_|
| physical_plan | ProjectionExec: expr=[sum(step_aggr_extended.val_col_3)@0 as sum(step_aggr_extended.val_col_3), count(step_aggr_extended.val_col_2)@1 as count(step_aggr_extended.val_col_2), count(step_aggr_extended.val_col_3)@2 as count(step_aggr_extended.val_col_3), count(Int64(1))@3 as count(*)]_|
|_|_AggregateExec: mode=Final, gby=[], aggr=[sum(step_aggr_extended.val_col_3), count(step_aggr_extended.val_col_2), count(step_aggr_extended.val_col_3), count(Int64(1))]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[sum(step_aggr_extended.val_col_3), count(step_aggr_extended.val_col_2), count(step_aggr_extended.val_col_3), count(Int64(1))]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- Case 16: Aggregation on STRING columns.
-- `MIN` and `MAX` can operate on strings.
-- Expected: Correct lexicographical min/max results.
SELECT MIN(pk_col_1), MAX(val_col_2) FROM step_aggr_extended;
+----------------------------------+-----------------------------------+
| min(step_aggr_extended.pk_col_1) | max(step_aggr_extended.val_col_2) |
+----------------------------------+-----------------------------------+
| a | v3 |
+----------------------------------+-----------------------------------+
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT MIN(pk_col_1), MAX(val_col_2) FROM step_aggr_extended;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__min_merge(__min_state(step_aggr_extended.pk_col_1)) AS min(step_aggr_extended.pk_col_1), __max_merge(__max_state(step_aggr_extended.val_col_2)) AS max(step_aggr_extended.val_col_2)]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__min_state(step_aggr_extended.pk_col_1), __max_state(step_aggr_extended.val_col_2)]]_|
|_|_TableScan: step_aggr_extended_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[min(step_aggr_extended.pk_col_1), max(step_aggr_extended.val_col_2)]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[min(step_aggr_extended.pk_col_1), max(step_aggr_extended.val_col_2)]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- Case 17: Aggregation on an empty input set.
-- `WHERE` clause filters out all rows.
-- Expected: Aggregation should return correct default values (e.g., COUNT is 0, SUM is NULL).
SELECT SUM(val_col_1), COUNT(*) FROM step_aggr_extended WHERE pk_col_1 = 'non_existent';
+-----------------------------------+----------+
| sum(step_aggr_extended.val_col_1) | count(*) |
+-----------------------------------+----------+
| | 0 |
+-----------------------------------+----------+
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT SUM(val_col_1), COUNT(*) FROM step_aggr_extended WHERE pk_col_1 = 'non_existent';
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Projection: sum(step_aggr_extended.val_col_1), count(Int64(1)) AS count(*)_|
|_|_Aggregate: groupBy=[[]], aggr=[[__sum_merge(__sum_state(step_aggr_extended.val_col_1)) AS sum(step_aggr_extended.val_col_1), __count_merge(__count_state(step_aggr_extended.ts)) AS count(Int64(1))]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__sum_state(step_aggr_extended.val_col_1), __count_state(step_aggr_extended.ts)]]_|
|_|_Filter: step_aggr_extended.pk_col_1 = Utf8("non_existent")_|
|_|_TableScan: step_aggr_extended_|
|_| ]]_|
| physical_plan | ProjectionExec: expr=[sum(step_aggr_extended.val_col_1)@0 as sum(step_aggr_extended.val_col_1), count(Int64(1))@1 as count(*)]_|
|_|_AggregateExec: mode=Final, gby=[], aggr=[sum(step_aggr_extended.val_col_1), count(Int64(1))]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[sum(step_aggr_extended.val_col_1), count(Int64(1))]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
DROP TABLE step_aggr_extended;
Affected Rows: 0

View File

@@ -305,3 +305,110 @@ GROUP BY
drop table aggr_optimize_not_count;
drop table aggr_optimize_not;
--
-- Additional test cases for step aggregation pushdown
--
CREATE TABLE step_aggr_extended (
pk_col_1 STRING,
pk_col_2 BIGINT,
val_col_1 BIGINT,
val_col_2 STRING,
val_col_3 BIGINT,
ts TIMESTAMP TIME INDEX,
PRIMARY KEY(pk_col_1, pk_col_2)
) PARTITION ON COLUMNS (pk_col_1) (
pk_col_1 < 'f',
pk_col_1 >= 'f'
);
INSERT INTO step_aggr_extended VALUES
('a', 1, 100, 'v1', 10, 1672531200000),
('a', 2, 200, 'v2', NULL, 1672531201000),
('g', 1, 300, 'v1', 30, 1672531202000),
('g', 2, 400, 'v2', 40, 1672531203000),
('a', 3, 100, 'v3', 10, 1672531204000),
('g', 3, 300, 'v3', 30, 1672531205000),
('h', 4, 500, NULL, 50, 1672531206000);
-- Case 12: GROUP BY includes a mix of partition key and non-partition key.
-- `pk_col_1` is a partition key, `pk_col_2` is not.
-- This should pushdown entire aggregation to datanodes since it's partitioned by `pk_col_1`.
-- Expected: Full pushdown of aggregation to datanodes.
SELECT pk_col_1, pk_col_2, sum(val_col_1) FROM step_aggr_extended GROUP BY pk_col_1, pk_col_2 ORDER BY pk_col_1, pk_col_2;
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT pk_col_1, pk_col_2, sum(val_col_1) FROM step_aggr_extended GROUP BY pk_col_1, pk_col_2 ORDER BY pk_col_1, pk_col_2;
-- Case 13: COUNT(DISTINCT) aggregation.
-- `DISTINCT` aggregation is more complex and requires a two-phase distinct calculation in a distributed environment. Currently not supported for pushdown.
-- Expected: datanode only do table scan, actual aggregation happens on frontend.
SELECT COUNT(DISTINCT val_col_1) FROM step_aggr_extended;
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT COUNT(DISTINCT val_col_1) FROM step_aggr_extended;
-- Case 14: Aggregation with a HAVING clause.
-- The `HAVING` clause filters results after aggregation.
-- Expected: The `HAVING` filter should be applied on the frontend after the final aggregation is complete, not pushed down to datanodes.
SELECT pk_col_2, sum(val_col_1) FROM step_aggr_extended GROUP BY pk_col_2 HAVING sum(val_col_1) > 300 ORDER BY pk_col_2;
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT pk_col_2, sum(val_col_1) FROM step_aggr_extended GROUP BY pk_col_2 HAVING sum(val_col_1) > 300 ORDER BY pk_col_2;
-- Case 15: Aggregation on a column with NULL values.
-- `SUM` should ignore NULLs. `COUNT(val_col_2)` should count non-nulls, `COUNT(*)` should count all rows.
-- Expected: Correct aggregation results, proving NULLs are handled properly in a distributed context.
SELECT SUM(val_col_3), COUNT(val_col_2), COUNT(val_col_3), COUNT(*) FROM step_aggr_extended;
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT SUM(val_col_3), COUNT(val_col_2), COUNT(val_col_3), COUNT(*) FROM step_aggr_extended;
-- Case 16: Aggregation on STRING columns.
-- `MIN` and `MAX` can operate on strings.
-- Expected: Correct lexicographical min/max results.
SELECT MIN(pk_col_1), MAX(val_col_2) FROM step_aggr_extended;
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT MIN(pk_col_1), MAX(val_col_2) FROM step_aggr_extended;
-- Case 17: Aggregation on an empty input set.
-- `WHERE` clause filters out all rows.
-- Expected: Aggregation should return correct default values (e.g., COUNT is 0, SUM is NULL).
SELECT SUM(val_col_1), COUNT(*) FROM step_aggr_extended WHERE pk_col_1 = 'non_existent';
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (Hash.*) REDACTED
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
EXPLAIN SELECT SUM(val_col_1), COUNT(*) FROM step_aggr_extended WHERE pk_col_1 = 'non_existent';
DROP TABLE step_aggr_extended;

View File

@@ -14,13 +14,17 @@ Affected Rows: 0
INSERT INTO
integers (host, i, ts)
VALUES
('220-A', 2, '2023-01-01 00:00:00'),
('220-B', 3, '2023-01-01 00:00:00'),
('550-A', 1, '2023-01-01 00:00:00'),
('550-B', 5, '2023-01-01 00:00:00'),
('550-A', 2, '2023-01-01 01:00:00'),
('550-W', 3, '2023-01-01 02:00:00'),
('550-W', 4, '2023-01-01 03:00:00');
('550-Z', 4, '2023-01-01 02:00:00'),
('550-W', 5, '2023-01-01 03:00:00'),
('550-Z', 6, '2023-01-01 03:00:00');
Affected Rows: 5
Affected Rows: 9
-- count
SELECT
@@ -31,7 +35,7 @@ FROM
+-------------------+
| count(integers.i) |
+-------------------+
| 5 |
| 9 |
+-------------------+
-- SQLNESS REPLACE (-+) -
@@ -120,10 +124,10 @@ ORDER BY
+---------------------+-------------------+
| ts | count(integers.i) |
+---------------------+-------------------+
| 2023-01-01T00:00:00 | 2 |
| 2023-01-01T00:00:00 | 4 |
| 2023-01-01T01:00:00 | 1 |
| 2023-01-01T02:00:00 | 1 |
| 2023-01-01T03:00:00 | 1 |
| 2023-01-01T02:00:00 | 2 |
| 2023-01-01T03:00:00 | 2 |
+---------------------+-------------------+
-- SQLNESS REPLACE (-+) -
@@ -234,10 +238,10 @@ ORDER BY
+---------------------+-------------------+
| time_window | count(integers.i) |
+---------------------+-------------------+
| 2023-01-01T00:00:00 | 2 |
| 2023-01-01T00:00:00 | 4 |
| 2023-01-01T01:00:00 | 1 |
| 2023-01-01T02:00:00 | 1 |
| 2023-01-01T03:00:00 | 1 |
| 2023-01-01T02:00:00 | 2 |
| 2023-01-01T03:00:00 | 2 |
+---------------------+-------------------+
-- SQLNESS REPLACE (-+) -
@@ -260,15 +264,20 @@ ORDER BY
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: time_window ASC NULLS LAST, count(integers.i) ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: time_window ASC NULLS LAST, count(integers.i) ASC NULLS LAST_|
| logical_plan_| Sort: time_window ASC NULLS LAST, count(integers.i) ASC NULLS LAST_|
|_|_Projection: date_bin(Utf8("1 hour"),integers.ts) AS time_window, count(integers.i)_|
|_|_Aggregate: groupBy=[[date_bin(CAST(Utf8("1 hour") AS Interval(MonthDayNano)), integers.ts)]], aggr=[[count(integers.i)]] |
|_|_Aggregate: groupBy=[[date_bin(Utf8("1 hour"),integers.ts)]], aggr=[[__count_merge(__count_state(integers.i)) AS count(integers.i)]]_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("1 hour") AS Interval(MonthDayNano)), integers.ts)]], aggr=[[__count_state(integers.i)]]_|
|_|_TableScan: integers_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_SortExec: expr=[time_window@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST], preserve_partitioning=[true]_|
|_|_ProjectionExec: expr=[date_bin(Utf8("1 hour"),integers.ts)@0 as time_window, count(integers.i)@1 as count(integers.i)]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] |
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: partitioning=REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
@@ -299,37 +308,33 @@ ORDER BY
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SortExec: expr=[time_window@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_ProjectionExec: expr=[date_bin(Utf8("1 hour"),integers.ts)@0 as time_window, count(integers.i)@1 as count(integers.i)] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[date_bin(Utf8("1 hour"),integers.ts)@0 as time_window, count(integers.i)@1 as count(integers.i)] REDACTED
|_|_|_SortPreservingMergeExec: [date_bin(Utf8("1 hour"),integers.ts)@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[date_bin(Utf8("1 hour"),integers.ts)@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] REDACTED
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 3600000000000 }, ts@1) as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 3600000000000 }, ts@1) as date_bin(Utf8("1 hour"),integers.ts)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_ProjectionExec: expr=[date_bin(Utf8("1 hour"),integers.ts)@0 as time_window, count(integers.i)@1 as count(integers.i)] REDACTED
|_|_|_SortPreservingMergeExec: [date_bin(Utf8("1 hour"),integers.ts)@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[date_bin(Utf8("1 hour"),integers.ts)@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] REDACTED
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 3600000000000 }, ts@1) as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 3600000000000 }, ts@1) as date_bin(Utf8("1 hour"),integers.ts)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_ProjectionExec: expr=[date_bin(Utf8("1 hour"),integers.ts)@0 as time_window, count(integers.i)@1 as count(integers.i)] REDACTED
|_|_|_SortPreservingMergeExec: [date_bin(Utf8("1 hour"),integers.ts)@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[date_bin(Utf8("1 hour"),integers.ts)@0 ASC NULLS LAST, count(integers.i)@1 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] REDACTED
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("1 hour"),integers.ts)@0 as date_bin(Utf8("1 hour"),integers.ts)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 3600000000000 }, ts@1) as date_bin(Utf8("1 hour"),integers.ts)], aggr=[count(integers.i)] REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 3600000000000 }, ts@1) as date_bin(Utf8("1 hour"),integers.ts)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
@@ -354,10 +359,13 @@ ORDER BY
| integers.ts + Int64(1) | integers.i / Int64(2) | count(integers.i) |
+------------------------+-----------------------+-------------------+
| 1672531200001 | 0 | 1 |
| 1672531200001 | 1 | 2 |
| 1672531200001 | 2 | 1 |
| 1672534800001 | 1 | 1 |
| 1672538400001 | 1 | 1 |
| 1672538400001 | 2 | 1 |
| 1672542000001 | 2 | 1 |
| 1672542000001 | 3 | 1 |
+------------------------+-----------------------+-------------------+
-- SQLNESS REPLACE (-+) -
@@ -383,15 +391,18 @@ ORDER BY
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: integers.ts + Int64(1) ASC NULLS LAST, integers.i / Int64(2) ASC NULLS LAST_|
| logical_plan_| Sort: integers.ts + Int64(1) ASC NULLS LAST, integers.i / Int64(2) ASC NULLS LAST_|
|_|_Aggregate: groupBy=[[integers.ts + Int64(1), integers.i / Int64(2)]], aggr=[[__count_merge(__count_state(integers.i)) AS count(integers.i)]]_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: integers.ts + Int64(1) ASC NULLS LAST, integers.i / Int64(2) ASC NULLS LAST_|
|_|_Projection: integers.ts + Int64(1), integers.i / Int64(2), count(integers.i)_|
|_|_Aggregate: groupBy=[[CAST(integers.ts AS Int64) + Int64(1), integers.i / Int64(2)]], aggr=[[count(integers.i)]] |
|_| Aggregate: groupBy=[[CAST(integers.ts AS Int64) + Int64(1), integers.i / Int64(2)]], aggr=[[__count_state(integers.i)]]_|
|_|_TableScan: integers_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_SortExec: expr=[integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST], preserve_partitioning=[true]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[count(integers.i)] |
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: partitioning=REDACTED
|_|_AggregateExec: mode=Partial, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[count(integers.i)]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
@@ -425,38 +436,36 @@ ORDER BY
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SortExec: expr=[integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[count(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[count(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_SortPreservingMergeExec: [integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[count(integers.i)] REDACTED
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[CAST(ts@1 AS Int64) + 1 as integers.ts + Int64(1), i@0 / 2 as integers.i / Int64(2)], aggr=[count(integers.i)] REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[CAST(ts@1 AS Int64) + 1 as integers.ts + Int64(1), i@0 / 2 as integers.i / Int64(2)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_SortPreservingMergeExec: [integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[count(integers.i)] REDACTED
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[CAST(ts@1 AS Int64) + 1 as integers.ts + Int64(1), i@0 / 2 as integers.i / Int64(2)], aggr=[count(integers.i)] REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[CAST(ts@1 AS Int64) + 1 as integers.ts + Int64(1), i@0 / 2 as integers.i / Int64(2)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_SortPreservingMergeExec: [integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[integers.ts + Int64(1)@0 ASC NULLS LAST, integers.i / Int64(2)@1 ASC NULLS LAST], preserve_partitioning=[true] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[count(integers.i)] REDACTED
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[integers.ts + Int64(1)@0 as integers.ts + Int64(1), integers.i / Int64(2)@1 as integers.i / Int64(2)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: partitioning=REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[CAST(ts@1 AS Int64) + 1 as integers.ts + Int64(1), i@0 / 2 as integers.i / Int64(2)], aggr=[count(integers.i)] REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[CAST(ts@1 AS Int64) + 1 as integers.ts + Int64(1), i@0 / 2 as integers.i / Int64(2)], aggr=[__count_state(integers.i)] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 5_|
|_|_| Total rows: 8_|
+-+-+-+
-- test udd/hll_merege pushdown
@@ -487,7 +496,7 @@ GROUP BY
time_window,
host;
Affected Rows: 5
Affected Rows: 9
SELECT
uddsketch_calc(0.5, uddsketch_merge(128, 0.01, udd_state)) as udd_result,
@@ -498,7 +507,7 @@ FROM
+--------------------+------------+
| udd_result | hll_result |
+--------------------+------------+
| 2.9742334234767016 | 5 |
| 2.9742334234767016 | 6 |
+--------------------+------------+
-- SQLNESS REPLACE (-+) -

View File

@@ -12,11 +12,15 @@ CREATE TABLE integers(
INSERT INTO
integers (host, i, ts)
VALUES
('220-A', 2, '2023-01-01 00:00:00'),
('220-B', 3, '2023-01-01 00:00:00'),
('550-A', 1, '2023-01-01 00:00:00'),
('550-B', 5, '2023-01-01 00:00:00'),
('550-A', 2, '2023-01-01 01:00:00'),
('550-W', 3, '2023-01-01 02:00:00'),
('550-W', 4, '2023-01-01 03:00:00');
('550-Z', 4, '2023-01-01 02:00:00'),
('550-W', 5, '2023-01-01 03:00:00'),
('550-Z', 6, '2023-01-01 03:00:00');
-- count
SELECT

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,827 @@
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
) with (append_mode='true');
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
admin flush_table('t');
+------------------------+
| ADMIN flush_table('t') |
+------------------------+
| 0 |
+------------------------+
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by host;
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
| first_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
| a | 🌕 | 1.0 |
| b | 🌖 | 2.0 |
| c | 🌘 | 4.0 |
| d | 🌕 | 9.0 |
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
-- repeat the query again, ref: https://github.com/GreptimeTeam/greptimedb/issues/4650
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by host;
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
| first_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
| a | 🌕 | 1.0 |
| b | 🌖 | 2.0 |
| c | 🌘 | 4.0 |
| d | 🌕 | 9.0 |
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_UnorderedScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":0, "files":1, "file_ranges":1} REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select first_value(ts order by ts) from t;
+--------------------------------------------------+
| first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+--------------------------------------------------+
| 1970-01-01T00:00:00 |
+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select first_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[]], aggr=[[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select first_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_UnorderedScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":0, "files":1, "file_ranges":1} REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
drop table t;
Affected Rows: 0
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
);
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
+--------------+------------------------------------------------------+---------------------------------------------------+
| ordered_host | first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+--------------+------------------------------------------------------+---------------------------------------------------+
| a | 🌕 | 1.0 |
| b | 🌖 | 2.0 |
| c | 🌘 | 4.0 |
| d | 🌕 | 9.0 |
+--------------+------------------------------------------------------+---------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: ordered_host ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: ordered_host ASC NULLS LAST_|
|_|_Projection: first_value(t.host) ORDER BY [t.ts ASC NULLS LAST] AS ordered_host, first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 as ordered_host, first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@1 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 as ordered_host, first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@1 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 as ordered_host, first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@1 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select first_value(ts order by ts) from t;
+--------------------------------------------------+
| first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+--------------------------------------------------+
| 1970-01-01T00:00:00 |
+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select first_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__first_value_merge(__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]) AS first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]]]_|
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select first_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+--------------+---------------------------------------------------+--------------------------------------------------+-------------------------+
| ordered_host | first_value(t.val) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] | time_window |
+--------------+---------------------------------------------------+--------------------------------------------------+-------------------------+
| a | 1.0 | 1970-01-01T00:00:00 | 1970-01-01T00:00:00 |
| b | 6.0 | 1970-01-01T00:00:00.005 | 1970-01-01T00:00:00.005 |
+--------------+---------------------------------------------------+--------------------------------------------------+-------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST, ordered_host ASC NULLS LAST_|
|_|_Projection: first_value(t.host) ORDER BY [t.ts ASC NULLS LAST] AS ordered_host, first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts) AS time_window_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("5 milliseconds"),t.ts)]], aggr=[[__first_value_merge(__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST]) AS first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_merge(__first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST]) AS first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_merge(__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]) AS first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("5 milliseconds") AS Interval(MonthDayNano)), t.ts)]], aggr=[[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]]]_|
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts)@0 as time_window]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts)@0 as time_window] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 2_|
+-+-+-+
drop table t;
Affected Rows: 0
CREATE TABLE phy (ts timestamp time index, val double, host string primary key)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
) engine=metric with ("physical_metric_table" = "");
Affected Rows: 0
CREATE TABLE t1 (ts timestamp time index, val double, host string primary key) engine = metric with ("on_physical_table" = "phy");
Affected Rows: 0
insert into
t1(ts, val, host)
values
(0, 1.0, 'a'),
(1, 2.0, 'b'),
(2, 3.0, 'a'),
(3, 4.0, 'c'),
(4, 5.0, 'a'),
(5, 6.0, 'b'),
(6, 7.0, 'a'),
(7, 8.0, 'c'),
(8, 9.0, 'd');
Affected Rows: 9
select first_value(ts order by ts) from t1;
+----------------------------------------------------+
| first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST] |
+----------------------------------------------------+
| 1970-01-01T00:00:00 |
+----------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select first_value(ts order by ts) from t1;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__first_value_merge(__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]) AS first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]]_|
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select first_value(ts order by ts) from t1;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
+--------------+-----------------------------------------------------+
| ordered_host | first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST] |
+--------------+-----------------------------------------------------+
| a | 1.0 |
| b | 2.0 |
| c | 4.0 |
| d | 9.0 |
+--------------+-----------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: ordered_host ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: ordered_host ASC NULLS LAST_|
|_|_Projection: first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST] AS ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t1.host]], aggr=[[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@1 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@1 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@1 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+--------------+-----------------------------------------------------+----------------------------------------------------+-------------------------+
| ordered_host | first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST] | first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST] | time_window |
+--------------+-----------------------------------------------------+----------------------------------------------------+-------------------------+
| a | 1.0 | 1970-01-01T00:00:00 | 1970-01-01T00:00:00 |
| b | 6.0 | 1970-01-01T00:00:00.005 | 1970-01-01T00:00:00.005 |
+--------------+-----------------------------------------------------+----------------------------------------------------+-------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST, ordered_host ASC NULLS LAST_|
|_|_Projection: first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST] AS ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts) AS time_window_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("5 milliseconds"),t1.ts)]], aggr=[[__first_value_merge(__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST]) AS first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_merge(__first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST]) AS first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_merge(__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]) AS first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("5 milliseconds") AS Interval(MonthDayNano)), t1.ts)]], aggr=[[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]]_|
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]@3 as first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts)@0 as time_window]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]@3 as first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts)@0 as time_window] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 2_|
+-+-+-+
drop table t1;
Affected Rows: 0
drop table phy;
Affected Rows: 0

View File

@@ -0,0 +1 @@
../../standalone/optimizer/first_value_advance.sql

View File

@@ -0,0 +1,827 @@
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
) with (append_mode='true');
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
admin flush_table('t');
+------------------------+
| ADMIN flush_table('t') |
+------------------------+
| 0 |
+------------------------+
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
-- repeat the query again, ref: https://github.com/GreptimeTeam/greptimedb/issues/4650
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":0, "files":1, "file_ranges":1}, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select last_value(ts order by ts) from t;
+-------------------------------------------------+
| last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+-------------------------------------------------+
| 1970-01-01T00:00:00.008 |
+-------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select last_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[]], aggr=[[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select last_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":0, "files":1, "file_ranges":1}, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
drop table t;
Affected Rows: 0
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
);
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
+--------------+-----------------------------------------------------+--------------------------------------------------+
| ordered_host | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+--------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+--------------+-----------------------------------------------------+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: ordered_host ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: ordered_host ASC NULLS LAST_|
|_|_Projection: last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] AS ordered_host, last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 as ordered_host, last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@1 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 1_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 as ordered_host, last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@1 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 2_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 as ordered_host, last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@1 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select last_value(ts order by ts) from t;
+-------------------------------------------------+
| last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+-------------------------------------------------+
| 1970-01-01T00:00:00.008 |
+-------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select last_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__last_value_merge(__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]) AS last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]]]_|
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select last_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+--------------+--------------------------------------------------+-------------------------------------------------+-------------------------+
| ordered_host | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] | time_window |
+--------------+--------------------------------------------------+-------------------------------------------------+-------------------------+
| a | 5.0 | 1970-01-01T00:00:00.004 | 1970-01-01T00:00:00 |
| d | 9.0 | 1970-01-01T00:00:00.008 | 1970-01-01T00:00:00.005 |
+--------------+--------------------------------------------------+-------------------------------------------------+-------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST, ordered_host ASC NULLS LAST_|
|_|_Projection: last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] AS ordered_host, last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts) AS time_window_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("5 milliseconds"),t.ts)]], aggr=[[__last_value_merge(__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST]) AS last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_merge(__last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST]) AS last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_merge(__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]) AS last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("5 milliseconds") AS Interval(MonthDayNano)), t.ts)]], aggr=[[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]]]_|
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts)@0 as time_window]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts)@0 as time_window] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 2_|
+-+-+-+
drop table t;
Affected Rows: 0
CREATE TABLE phy (ts timestamp time index, val double, host string primary key)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
) engine=metric with ("physical_metric_table" = "");
Affected Rows: 0
CREATE TABLE t1 (ts timestamp time index, val double, host string primary key) engine = metric with ("on_physical_table" = "phy");
Affected Rows: 0
insert into
t1(ts, val, host)
values
(0, 1.0, 'a'),
(1, 2.0, 'b'),
(2, 3.0, 'a'),
(3, 4.0, 'c'),
(4, 5.0, 'a'),
(5, 6.0, 'b'),
(6, 7.0, 'a'),
(7, 8.0, 'c'),
(8, 9.0, 'd');
Affected Rows: 9
select last_value(ts order by ts) from t1;
+---------------------------------------------------+
| last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST] |
+---------------------------------------------------+
| 1970-01-01T00:00:00.008 |
+---------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select last_value(ts order by ts) from t1;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__last_value_merge(__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]) AS last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]]_|
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select last_value(ts order by ts) from t1;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
+--------------+----------------------------------------------------+
| ordered_host | last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST] |
+--------------+----------------------------------------------------+
| a | 7.0 |
| b | 6.0 |
| c | 8.0 |
| d | 9.0 |
+--------------+----------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: ordered_host ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: ordered_host ASC NULLS LAST_|
|_|_Projection: last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST] AS ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t1.host]], aggr=[[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@1 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 1_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@1 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 2_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@1 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_SortPreservingMergeExec: [last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+--------------+----------------------------------------------------+---------------------------------------------------+-------------------------+
| ordered_host | last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST] | last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST] | time_window |
+--------------+----------------------------------------------------+---------------------------------------------------+-------------------------+
| a | 5.0 | 1970-01-01T00:00:00.004 | 1970-01-01T00:00:00 |
| d | 9.0 | 1970-01-01T00:00:00.008 | 1970-01-01T00:00:00.005 |
+--------------+----------------------------------------------------+---------------------------------------------------+-------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST, ordered_host ASC NULLS LAST_|
|_|_Projection: last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST] AS ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts) AS time_window_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("5 milliseconds"),t1.ts)]], aggr=[[__last_value_merge(__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST]) AS last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_merge(__last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST]) AS last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_merge(__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]) AS last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("5 milliseconds") AS Interval(MonthDayNano)), t1.ts)]], aggr=[[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]]_|
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]@3 as last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts)@0 as time_window]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]@3 as last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts)@0 as time_window] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 2_|
+-+-+-+
drop table t1;
Affected Rows: 0
drop table phy;
Affected Rows: 0

View File

@@ -0,0 +1 @@
../../standalone/optimizer/last_value_advance.sql

View File

@@ -386,6 +386,35 @@ select ts, count(*) from logical_table_4 GROUP BY ts ORDER BY ts;
|_|_|
+-+-+
select * from logical_table_4;
+-----------------------+-----+------+-------------------+---------------------+
| another_partition_key | cpu | host | one_partition_key | ts |
+-----------------------+-----+------+-------------------+---------------------+
| | 1.0 | | | 2023-01-01T00:00:00 |
| | 2.0 | | | 2023-01-01T00:00:01 |
| | 3.0 | | | 2023-01-01T00:00:02 |
+-----------------------+-----+------+-------------------+---------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (RepartitionExec:.*) RepartitionExec: REDACTED
EXPLAIN select * from logical_table_4;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: logical_table_4.another_partition_key, logical_table_4.cpu, logical_table_4.host, logical_table_4.one_partition_key, logical_table_4.ts |
|_|_TableScan: logical_table_4_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
drop table logical_table_2;
Affected Rows: 0

View File

@@ -140,6 +140,15 @@ select ts, count(*) from logical_table_4 GROUP BY ts ORDER BY ts;
EXPLAIN
select ts, count(*) from logical_table_4 GROUP BY ts ORDER BY ts;
select * from logical_table_4;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (RepartitionExec:.*) RepartitionExec: REDACTED
EXPLAIN select * from logical_table_4;
drop table logical_table_2;
drop table logical_table_3;

View File

@@ -31,7 +31,7 @@ SELECT
FROM accounts a
LEFT JOIN transactions t ON a.acc_id = t.acc_id
GROUP BY a.acc_id, a.acc_name, a.balance
ORDER BY transaction_count DESC;
ORDER BY transaction_count DESC, total_activity DESC;
+------------+---------+-------------------+----------------+
| acc_name | balance | transaction_count | total_activity |

View File

@@ -24,7 +24,7 @@ SELECT
FROM accounts a
LEFT JOIN transactions t ON a.acc_id = t.acc_id
GROUP BY a.acc_id, a.acc_name, a.balance
ORDER BY transaction_count DESC;
ORDER BY transaction_count DESC, total_activity DESC;
-- Left join with date filtering
SELECT

View File

@@ -1,69 +0,0 @@
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
) with (append_mode='true');
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
admin flush_table('t');
+------------------------+
| ADMIN flush_table('t') |
+------------------------+
| 0 |
+------------------------+
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
-- repeat the query again, ref: https://github.com/GreptimeTeam/greptimedb/issues/4650
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
drop table t;
Affected Rows: 0

View File

@@ -1,38 +0,0 @@
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
) with (append_mode='true');
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
admin flush_table('t');
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
-- repeat the query again, ref: https://github.com/GreptimeTeam/greptimedb/issues/4650
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
drop table t;

View File

@@ -240,9 +240,9 @@ select * from information_schema.columns order by table_schema, table_name, colu
| greptime | information_schema | parameters | specific_name | 3 | 2147483647 | 2147483647 | | | | utf8 | utf8_bin | | | select,insert | | String | string | FIELD | | No | string | | |
| greptime | information_schema | parameters | specific_schema | 2 | 2147483647 | 2147483647 | | | | utf8 | utf8_bin | | | select,insert | | String | string | FIELD | | No | string | | |
| greptime | information_schema | partitions | avg_row_length | 14 | | | 19 | 0 | | | | | | select,insert | | Int64 | bigint | FIELD | | Yes | bigint | | |
| greptime | information_schema | partitions | check_time | 21 | | | | | 6 | | | | | select,insert | | TimestampMicrosecond | timestamp(6) | FIELD | | Yes | timestamp(6) | | |
| greptime | information_schema | partitions | check_time | 21 | | | | | 0 | | | | | select,insert | | TimestampSecond | timestamp(0) | FIELD | | Yes | timestamp(0) | | |
| greptime | information_schema | partitions | checksum | 22 | | | 19 | 0 | | | | | | select,insert | | Int64 | bigint | FIELD | | Yes | bigint | | |
| greptime | information_schema | partitions | create_time | 19 | | | | | 6 | | | | | select,insert | | TimestampMicrosecond | timestamp(6) | FIELD | | Yes | timestamp(6) | | |
| greptime | information_schema | partitions | create_time | 19 | | | | | 0 | | | | | select,insert | | TimestampSecond | timestamp(0) | FIELD | | Yes | timestamp(0) | | |
| greptime | information_schema | partitions | data_free | 18 | | | 19 | 0 | | | | | | select,insert | | Int64 | bigint | FIELD | | Yes | bigint | | |
| greptime | information_schema | partitions | data_length | 15 | | | 19 | 0 | | | | | | select,insert | | Int64 | bigint | FIELD | | Yes | bigint | | |
| greptime | information_schema | partitions | greptime_partition_id | 26 | | | 20 | 0 | | | | | | select,insert | | UInt64 | bigint unsigned | FIELD | | Yes | bigint unsigned | | |
@@ -264,7 +264,7 @@ select * from information_schema.columns order by table_schema, table_name, colu
| greptime | information_schema | partitions | table_rows | 13 | | | 19 | 0 | | | | | | select,insert | | Int64 | bigint | FIELD | | Yes | bigint | | |
| greptime | information_schema | partitions | table_schema | 2 | 2147483647 | 2147483647 | | | | utf8 | utf8_bin | | | select,insert | | String | string | FIELD | | No | string | | |
| greptime | information_schema | partitions | tablespace_name | 25 | 2147483647 | 2147483647 | | | | utf8 | utf8_bin | | | select,insert | | String | string | FIELD | | Yes | string | | |
| greptime | information_schema | partitions | update_time | 20 | | | | | 6 | | | | | select,insert | | TimestampMicrosecond | timestamp(6) | FIELD | | Yes | timestamp(6) | | |
| greptime | information_schema | partitions | update_time | 20 | | | | | 0 | | | | | select,insert | | TimestampSecond | timestamp(0) | FIELD | | Yes | timestamp(0) | | |
| greptime | information_schema | procedure_info | end_time | 4 | | | | | 3 | | | | | select,insert | | TimestampMillisecond | timestamp(3) | FIELD | | Yes | timestamp(3) | | |
| greptime | information_schema | procedure_info | lock_keys | 6 | 2147483647 | 2147483647 | | | | utf8 | utf8_bin | | | select,insert | | String | string | FIELD | | Yes | string | | |
| greptime | information_schema | procedure_info | procedure_id | 1 | 2147483647 | 2147483647 | | | | utf8 | utf8_bin | | | select,insert | | String | string | FIELD | | No | string | | |

View File

@@ -97,6 +97,7 @@ TQL EXPLAIN VERBOSE (0, 10, '5s') test;
|_|_Filter: test.j >= TimestampMillisecond(-300000, None) AND test.j <= TimestampMillisecond(300000, None)_|
|_|_TableScan: test_|
|_| ]]_|
| logical_plan after FixStateUdafOrderingAnalyzer_| SAME TEXT AS ABOVE_|
| analyzed_logical_plan_| SAME TEXT AS ABOVE_|
| logical_plan after eliminate_nested_union_| SAME TEXT AS ABOVE_|
| logical_plan after simplify_expressions_| SAME TEXT AS ABOVE_|

View File

@@ -274,3 +274,95 @@ drop table test;
Affected Rows: 0
CREATE TABLE metrics(val DOUBLE, ts TIMESTAMP TIME INDEX, host STRING PRIMARY KEY);
Affected Rows: 0
-- Insert sample data with fixed timestamps for predictable testing
INSERT INTO metrics VALUES
(10.0, '2024-01-01 00:00:00', 'host1'),
(15.0, '2024-01-01 06:00:00', 'host1'),
(20.0, '2024-01-01 12:00:00', 'host1'),
(25.0, '2024-01-01 18:00:00', 'host1'),
(30.0, '2024-01-02 00:00:00', 'host1'),
(35.0, '2024-01-02 06:00:00', 'host1'),
(40.0, '2024-01-02 12:00:00', 'host1'),
(12.0, '2024-01-01 02:00:00', 'host2'),
(18.0, '2024-01-01 08:00:00', 'host2'),
(22.0, '2024-01-01 14:00:00', 'host2');
Affected Rows: 10
-- Test TQL with date_trunc function
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (date_trunc('day', '2024-01-01 10:00:00'::timestamp),
date_trunc('day', '2024-01-02 10:00:00'::timestamp),
'6h') last_over_time(metrics[12h]);
+---------------------+-----------------------------------+-------+
| ts | prom_last_over_time(ts_range,val) | host |
+---------------------+-----------------------------------+-------+
| 2024-01-01T00:00:00 | 10.0 | host1 |
| 2024-01-01T06:00:00 | 12.0 | host2 |
| 2024-01-01T06:00:00 | 15.0 | host1 |
| 2024-01-01T12:00:00 | 18.0 | host2 |
| 2024-01-01T12:00:00 | 20.0 | host1 |
| 2024-01-01T18:00:00 | 22.0 | host2 |
| 2024-01-01T18:00:00 | 25.0 | host1 |
| 2024-01-02T00:00:00 | 22.0 | host2 |
| 2024-01-02T00:00:00 | 25.0 | host1 |
+---------------------+-----------------------------------+-------+
-- Test TQL with date_trunc and interval arithmetic (now() - interval '1' day pattern)
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (date_trunc('day', '2024-01-02 00:00:00'::timestamp) - interval '1' day,
date_trunc('day', '2024-01-02 00:00:00'::timestamp),
'4h') metrics{host="host1"};
+------+---------------------+-------+
| val | ts | host |
+------+---------------------+-------+
| 10.0 | 2024-01-01T00:00:00 | host1 |
| 20.0 | 2024-01-01T12:00:00 | host1 |
+------+---------------------+-------+
-- Test TQL with hour-based queries
-- SQLNESS SORT_RESULT 2 1
TQL EVAL ('2024-01-01 06:00:00'::timestamp,
'2024-01-01 18:00:00'::timestamp,
'3h',
'6h') metrics;
+------+---------------------+-------+
| val | ts | host |
+------+---------------------+-------+
| 12.0 | 2024-01-01T06:00:00 | host2 |
| 15.0 | 2024-01-01T06:00:00 | host1 |
| 15.0 | 2024-01-01T09:00:00 | host1 |
| 18.0 | 2024-01-01T09:00:00 | host2 |
| 18.0 | 2024-01-01T12:00:00 | host2 |
| 20.0 | 2024-01-01T12:00:00 | host1 |
| 20.0 | 2024-01-01T15:00:00 | host1 |
| 22.0 | 2024-01-01T15:00:00 | host2 |
| 22.0 | 2024-01-01T18:00:00 | host2 |
| 25.0 | 2024-01-01T18:00:00 | host1 |
+------+---------------------+-------+
-- Test TQL with complex interval arithmetic
-- SQLNESS SORT_RESULT 2 1
TQL EVAL ('2024-01-01 00:00:00'::timestamp + interval '12' hour,
'2024-01-02 00:00:00'::timestamp - interval '6' hour,
'6h',
'6h') metrics{host="host2"};
+------+---------------------+-------+
| val | ts | host |
+------+---------------------+-------+
| 18.0 | 2024-01-01T12:00:00 | host2 |
| 22.0 | 2024-01-01T18:00:00 | host2 |
+------+---------------------+-------+
DROP TABLE metrics;
Affected Rows: 0

View File

@@ -58,3 +58,46 @@ TQL EVAL (0, 10, '5s') test{__field__="Field_I"};
TQL EVAL (0, 10, '5s') test{__field__="field_i"};
drop table test;
CREATE TABLE metrics(val DOUBLE, ts TIMESTAMP TIME INDEX, host STRING PRIMARY KEY);
-- Insert sample data with fixed timestamps for predictable testing
INSERT INTO metrics VALUES
(10.0, '2024-01-01 00:00:00', 'host1'),
(15.0, '2024-01-01 06:00:00', 'host1'),
(20.0, '2024-01-01 12:00:00', 'host1'),
(25.0, '2024-01-01 18:00:00', 'host1'),
(30.0, '2024-01-02 00:00:00', 'host1'),
(35.0, '2024-01-02 06:00:00', 'host1'),
(40.0, '2024-01-02 12:00:00', 'host1'),
(12.0, '2024-01-01 02:00:00', 'host2'),
(18.0, '2024-01-01 08:00:00', 'host2'),
(22.0, '2024-01-01 14:00:00', 'host2');
-- Test TQL with date_trunc function
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (date_trunc('day', '2024-01-01 10:00:00'::timestamp),
date_trunc('day', '2024-01-02 10:00:00'::timestamp),
'6h') last_over_time(metrics[12h]);
-- Test TQL with date_trunc and interval arithmetic (now() - interval '1' day pattern)
-- SQLNESS SORT_RESULT 2 1
TQL EVAL (date_trunc('day', '2024-01-02 00:00:00'::timestamp) - interval '1' day,
date_trunc('day', '2024-01-02 00:00:00'::timestamp),
'4h') metrics{host="host1"};
-- Test TQL with hour-based queries
-- SQLNESS SORT_RESULT 2 1
TQL EVAL ('2024-01-01 06:00:00'::timestamp,
'2024-01-01 18:00:00'::timestamp,
'3h',
'6h') metrics;
-- Test TQL with complex interval arithmetic
-- SQLNESS SORT_RESULT 2 1
TQL EVAL ('2024-01-01 00:00:00'::timestamp + interval '12' hour,
'2024-01-02 00:00:00'::timestamp - interval '6' hour,
'6h',
'6h') metrics{host="host2"};
DROP TABLE metrics;

View File

@@ -81,3 +81,50 @@ drop schema "AnotherSchema";
Affected Rows: 0
create table metric (ts timestamp(3) time index, `AbCdE` string primary key, val double);
Affected Rows: 0
insert into metric values
(0, 'host1', 1),
(5000, 'host1', 2),
(10000, 'host1', 3),
(0, 'host2', 4),
(5000, 'host2', 5),
(10000, 'host2', 6);
Affected Rows: 6
-- which is actually group by nothing (invalid label name)
tql eval (0,10,'5s') sum by (abcde) (metric);
+---------------------+-----------------+
| ts | sum(metric.val) |
+---------------------+-----------------+
| 1970-01-01T00:00:00 | 5.0 |
| 1970-01-01T00:00:05 | 7.0 |
| 1970-01-01T00:00:10 | 9.0 |
+---------------------+-----------------+
tql eval (0,10,'5s') sum by (AbCdE) (metric);
+-------+---------------------+-----------------+
| AbCdE | ts | sum(metric.val) |
+-------+---------------------+-----------------+
| host1 | 1970-01-01T00:00:00 | 1.0 |
| host1 | 1970-01-01T00:00:05 | 2.0 |
| host1 | 1970-01-01T00:00:10 | 3.0 |
| host2 | 1970-01-01T00:00:00 | 4.0 |
| host2 | 1970-01-01T00:00:05 | 5.0 |
| host2 | 1970-01-01T00:00:10 | 6.0 |
+-------+---------------------+-----------------+
-- not allowed by the parser
tql eval (0,10,'5s') sum by (`AbCdE`) (metric);
Error: 2000(InvalidSyntax), invalid promql query
drop table metric;
Affected Rows: 0

View File

@@ -39,3 +39,23 @@ drop table "MemAvailable";
drop table "AnotherSchema"."MemTotal";
drop schema "AnotherSchema";
create table metric (ts timestamp(3) time index, `AbCdE` string primary key, val double);
insert into metric values
(0, 'host1', 1),
(5000, 'host1', 2),
(10000, 'host1', 3),
(0, 'host2', 4),
(5000, 'host2', 5),
(10000, 'host2', 6);
-- which is actually group by nothing (invalid label name)
tql eval (0,10,'5s') sum by (abcde) (metric);
tql eval (0,10,'5s') sum by (AbCdE) (metric);
-- not allowed by the parser
tql eval (0,10,'5s') sum by (`AbCdE`) (metric);
drop table metric;

View File

@@ -62,7 +62,7 @@ SELECT * FROM tql;
+---------------------+-----------+
-- Hybrid CTEs (TQL + SQL)
WITH
WITH
tql_data (ts, val) AS (TQL EVAL (0, 40, '10s') metric),
filtered AS (SELECT * FROM tql_data WHERE val > 5)
SELECT count(*) FROM filtered;
@@ -74,7 +74,7 @@ SELECT count(*) FROM filtered;
+----------+
-- TQL CTE with complex PromQL expressions
WITH
WITH
tql_data (ts, val) AS (TQL EVAL (0, 40, '10s') rate(metric[20s])),
filtered (ts, val) AS (SELECT * FROM tql_data WHERE val > 0)
SELECT sum(val) FROM filtered;
@@ -126,13 +126,13 @@ SELECT host_metrics.ts, host_metrics.host FROM host_metrics;
+---------------------+-------+
-- Multiple TQL CTEs referencing different tables
WITH
WITH
metric_data(ts, val) AS (TQL EVAL (0, 40, '10s') metric),
label_data(ts, host, cpu) AS (TQL EVAL (0, 40, '10s') labels{host="host2"})
SELECT
SELECT
m.val as metric_val,
l.cpu as label_val
FROM metric_data m, label_data l
FROM metric_data m, label_data l
WHERE m.ts = l.ts
ORDER BY m.ts
LIMIT 3;
@@ -161,7 +161,7 @@ SELECT min(val) as min_computed, max(val) as max_computed FROM computed;
WITH tql_base(ts, val) AS (
TQL EVAL (0, 40, '10s') metric
)
SELECT
SELECT
ts,
val,
LAG(val, 1) OVER (ORDER BY ts) as prev_value
@@ -182,10 +182,10 @@ ORDER BY ts;
WITH tql_grouped(ts, host, cpu) AS (
TQL EVAL (0, 40, '10s') labels
)
SELECT
SELECT
DATE_TRUNC('minute', ts) as minute,
count(*) as point_count
FROM tql_grouped
FROM tql_grouped
GROUP BY minute
HAVING count(*) > 1;
@@ -197,7 +197,7 @@ HAVING count(*) > 1;
-- TQL CTE with UNION
-- SQLNESS SORT_RESULT 3 1
WITH
WITH
host1_data(ts, host, cpu) AS (TQL EVAL (0, 40, '10s') labels{host="host1"}),
host2_data(ts, host, cpu) AS (TQL EVAL (0, 40, '10s') labels{host="host2"})
SELECT 'host1' as source, ts, cpu FROM host1_data
@@ -220,11 +220,11 @@ SELECT 'host2' as source, ts, cpu FROM host2_data;
+--------+---------------------+-----+
-- Nested CTEs with TQL
WITH
WITH
base_tql(ts, val) AS (TQL EVAL (0, 40, '10s') metric),
processed(ts, percent) AS (
SELECT ts, val * 100 as percent
FROM base_tql
SELECT ts, val * 100 as percent
FROM base_tql
WHERE val > 0
),
final(ts, percent) AS (
@@ -259,7 +259,7 @@ SELECT * FROM time_shifted;
WITH tql_summary(ts, host, cpu) AS (
TQL EVAL (0, 40, '10s') avg_over_time(labels[30s])
)
SELECT
SELECT
t.ts,
t.cpu as avg_value,
l.host
@@ -287,7 +287,7 @@ SELECT * FROM tql_analyze limit 1;
Error: 2000(InvalidSyntax), Invalid SQL, error: Only TQL EVAL is supported in CTEs
-- Error case - TQL EXPLAIN should fail
-- Error case - TQL EXPLAIN should fail
WITH tql_explain AS (
TQL EXPLAIN (0, 40, '10s') metric
)
@@ -297,7 +297,7 @@ Error: 2000(InvalidSyntax), Invalid SQL, error: Only TQL EVAL is supported in CT
-- TQL CTE with lookback parameter
WITH tql_lookback AS (
TQL EVAL (0, 40, '10s', 15s) metric
TQL EVAL (0, 40, '10s', '15s') metric
)
SELECT count(*) FROM tql_lookback;

View File

@@ -33,13 +33,13 @@ WITH tql (the_timestamp, the_value) as (
SELECT * FROM tql;
-- Hybrid CTEs (TQL + SQL)
WITH
WITH
tql_data (ts, val) AS (TQL EVAL (0, 40, '10s') metric),
filtered AS (SELECT * FROM tql_data WHERE val > 5)
SELECT count(*) FROM filtered;
-- TQL CTE with complex PromQL expressions
WITH
WITH
tql_data (ts, val) AS (TQL EVAL (0, 40, '10s') rate(metric[20s])),
filtered (ts, val) AS (SELECT * FROM tql_data WHERE val > 0)
SELECT sum(val) FROM filtered;
@@ -63,13 +63,13 @@ WITH host_metrics AS (
SELECT host_metrics.ts, host_metrics.host FROM host_metrics;
-- Multiple TQL CTEs referencing different tables
WITH
WITH
metric_data(ts, val) AS (TQL EVAL (0, 40, '10s') metric),
label_data(ts, host, cpu) AS (TQL EVAL (0, 40, '10s') labels{host="host2"})
SELECT
SELECT
m.val as metric_val,
l.cpu as label_val
FROM metric_data m, label_data l
FROM metric_data m, label_data l
WHERE m.ts = l.ts
ORDER BY m.ts
LIMIT 3;
@@ -84,7 +84,7 @@ SELECT min(val) as min_computed, max(val) as max_computed FROM computed;
WITH tql_base(ts, val) AS (
TQL EVAL (0, 40, '10s') metric
)
SELECT
SELECT
ts,
val,
LAG(val, 1) OVER (ORDER BY ts) as prev_value
@@ -95,16 +95,16 @@ ORDER BY ts;
WITH tql_grouped(ts, host, cpu) AS (
TQL EVAL (0, 40, '10s') labels
)
SELECT
SELECT
DATE_TRUNC('minute', ts) as minute,
count(*) as point_count
FROM tql_grouped
FROM tql_grouped
GROUP BY minute
HAVING count(*) > 1;
-- TQL CTE with UNION
-- SQLNESS SORT_RESULT 3 1
WITH
WITH
host1_data(ts, host, cpu) AS (TQL EVAL (0, 40, '10s') labels{host="host1"}),
host2_data(ts, host, cpu) AS (TQL EVAL (0, 40, '10s') labels{host="host2"})
SELECT 'host1' as source, ts, cpu FROM host1_data
@@ -112,11 +112,11 @@ UNION ALL
SELECT 'host2' as source, ts, cpu FROM host2_data;
-- Nested CTEs with TQL
WITH
WITH
base_tql(ts, val) AS (TQL EVAL (0, 40, '10s') metric),
processed(ts, percent) AS (
SELECT ts, val * 100 as percent
FROM base_tql
SELECT ts, val * 100 as percent
FROM base_tql
WHERE val > 0
),
final(ts, percent) AS (
@@ -135,7 +135,7 @@ SELECT * FROM time_shifted;
WITH tql_summary(ts, host, cpu) AS (
TQL EVAL (0, 40, '10s') avg_over_time(labels[30s])
)
SELECT
SELECT
t.ts,
t.cpu as avg_value,
l.host
@@ -151,7 +151,7 @@ WITH tql_analyze AS (
)
SELECT * FROM tql_analyze limit 1;
-- Error case - TQL EXPLAIN should fail
-- Error case - TQL EXPLAIN should fail
WITH tql_explain AS (
TQL EXPLAIN (0, 40, '10s') metric
)
@@ -159,7 +159,7 @@ SELECT * FROM tql_explain limit 1;
-- TQL CTE with lookback parameter
WITH tql_lookback AS (
TQL EVAL (0, 40, '10s', 15s) metric
TQL EVAL (0, 40, '10s', '15s') metric
)
SELECT count(*) FROM tql_lookback;

View File

@@ -0,0 +1,821 @@
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
) with (append_mode='true');
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
admin flush_table('t');
+------------------------+
| ADMIN flush_table('t') |
+------------------------+
| 0 |
+------------------------+
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by host;
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
| first_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
| a | 🌕 | 1.0 |
| b | 🌖 | 2.0 |
| c | 🌘 | 4.0 |
| d | 🌕 | 9.0 |
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
-- repeat the query again, ref: https://github.com/GreptimeTeam/greptimedb/issues/4650
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by host;
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
| first_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
| a | 🌕 | 1.0 |
| b | 🌖 | 2.0 |
| c | 🌘 | 4.0 |
| d | 🌕 | 9.0 |
+----------------------------------------------------+------------------------------------------------------+---------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_UnorderedScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":0, "files":1, "file_ranges":1} REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select first_value(ts order by ts) from t;
+--------------------------------------------------+
| first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+--------------------------------------------------+
| 1970-01-01T00:00:00 |
+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select first_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[]], aggr=[[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select first_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_UnorderedScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":0, "files":1, "file_ranges":1} REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
drop table t;
Affected Rows: 0
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
);
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
+--------------+------------------------------------------------------+---------------------------------------------------+
| ordered_host | first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+--------------+------------------------------------------------------+---------------------------------------------------+
| a | 🌕 | 1.0 |
| b | 🌖 | 2.0 |
| c | 🌘 | 4.0 |
| d | 🌕 | 9.0 |
+--------------+------------------------------------------------------+---------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: ordered_host ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: ordered_host ASC NULLS LAST_|
|_|_Projection: first_value(t.host) ORDER BY [t.ts ASC NULLS LAST] AS ordered_host, first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select first_value(ts order by ts) from t;
+--------------------------------------------------+
| first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+--------------------------------------------------+
| 1970-01-01T00:00:00 |
+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select first_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__first_value_merge(__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]) AS first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]]]_|
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select first_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+--------------+---------------------------------------------------+--------------------------------------------------+-------------------------+
| ordered_host | first_value(t.val) ORDER BY [t.ts ASC NULLS LAST] | first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] | time_window |
+--------------+---------------------------------------------------+--------------------------------------------------+-------------------------+
| a | 1.0 | 1970-01-01T00:00:00 | 1970-01-01T00:00:00 |
| b | 6.0 | 1970-01-01T00:00:00.005 | 1970-01-01T00:00:00.005 |
+--------------+---------------------------------------------------+--------------------------------------------------+-------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST, ordered_host ASC NULLS LAST_|
|_|_Projection: first_value(t.host) ORDER BY [t.ts ASC NULLS LAST] AS ordered_host, first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts) AS time_window_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("5 milliseconds"),t.ts)]], aggr=[[__first_value_merge(__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST]) AS first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_merge(__first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST]) AS first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_merge(__first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]) AS first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("5 milliseconds") AS Interval(MonthDayNano)), t.ts)]], aggr=[[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]]]_|
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts)@0 as time_window]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, first_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]@3 as first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts)@0 as time_window] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[first_value(t.host) ORDER BY [t.ts ASC NULLS LAST], first_value(t.val) ORDER BY [t.ts ASC NULLS LAST], first_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__first_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __first_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 2_|
+-+-+-+
drop table t;
Affected Rows: 0
CREATE TABLE phy (ts timestamp time index, val double, host string primary key)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
) engine=metric with ("physical_metric_table" = "");
Affected Rows: 0
CREATE TABLE t1 (ts timestamp time index, val double, host string primary key) engine = metric with ("on_physical_table" = "phy");
Affected Rows: 0
insert into
t1(ts, val, host)
values
(0, 1.0, 'a'),
(1, 2.0, 'b'),
(2, 3.0, 'a'),
(3, 4.0, 'c'),
(4, 5.0, 'a'),
(5, 6.0, 'b'),
(6, 7.0, 'a'),
(7, 8.0, 'c'),
(8, 9.0, 'd');
Affected Rows: 9
select first_value(ts order by ts) from t1;
+----------------------------------------------------+
| first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST] |
+----------------------------------------------------+
| 1970-01-01T00:00:00 |
+----------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select first_value(ts order by ts) from t1;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__first_value_merge(__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]) AS first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]]_|
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select first_value(ts order by ts) from t1;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=Final, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
+--------------+-----------------------------------------------------+
| ordered_host | first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST] |
+--------------+-----------------------------------------------------+
| a | 1.0 |
| b | 2.0 |
| c | 4.0 |
| d | 9.0 |
+--------------+-----------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: ordered_host ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: ordered_host ASC NULLS LAST_|
|_|_Projection: first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST] AS ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t1.host]], aggr=[[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+--------------+-----------------------------------------------------+----------------------------------------------------+-------------------------+
| ordered_host | first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST] | first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST] | time_window |
+--------------+-----------------------------------------------------+----------------------------------------------------+-------------------------+
| a | 1.0 | 1970-01-01T00:00:00 | 1970-01-01T00:00:00 |
| b | 6.0 | 1970-01-01T00:00:00.005 | 1970-01-01T00:00:00.005 |
+--------------+-----------------------------------------------------+----------------------------------------------------+-------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST, ordered_host ASC NULLS LAST_|
|_|_Projection: first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST] AS ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts) AS time_window_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("5 milliseconds"),t1.ts)]], aggr=[[__first_value_merge(__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST]) AS first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_merge(__first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST]) AS first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_merge(__first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]) AS first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("5 milliseconds") AS Interval(MonthDayNano)), t1.ts)]], aggr=[[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]]_|
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]@3 as first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts)@0 as time_window]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]@3 as first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts)@0 as time_window] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[first_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], first_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__first_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __first_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 2_|
+-+-+-+
drop table t1;
Affected Rows: 0
drop table phy;
Affected Rows: 0

View File

@@ -0,0 +1,344 @@
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
) with (append_mode='true');
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
admin flush_table('t');
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by host;
-- repeat the query again, ref: https://github.com/GreptimeTeam/greptimedb/issues/4650
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select
first_value(host order by ts),
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host;
select first_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select first_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select first_value(ts order by ts) from t;
drop table t;
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
);
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(not_pk order by ts),
first_value(val order by ts)
from t
group by host
order by ordered_host;
select first_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select first_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select first_value(ts order by ts) from t;
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
drop table t;
CREATE TABLE phy (ts timestamp time index, val double, host string primary key)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
) engine=metric with ("physical_metric_table" = "");
CREATE TABLE t1 (ts timestamp time index, val double, host string primary key) engine = metric with ("on_physical_table" = "phy");
insert into
t1(ts, val, host)
values
(0, 1.0, 'a'),
(1, 2.0, 'b'),
(2, 3.0, 'a'),
(3, 4.0, 'c'),
(4, 5.0, 'a'),
(5, 6.0, 'b'),
(6, 7.0, 'a'),
(7, 8.0, 'c'),
(8, 9.0, 'd');
select first_value(ts order by ts) from t1;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select first_value(ts order by ts) from t1;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select first_value(ts order by ts) from t1;
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts)
from t1
group by host
order by ordered_host;
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
first_value(host order by ts) as ordered_host,
first_value(val order by ts),
first_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
drop table t1;
drop table phy;

View File

@@ -20,6 +20,47 @@ insert into t values
Affected Rows: 9
select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
+--------------+-----------------------------------------------------+--------------------------------------------------+
| ordered_host | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+--------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+--------------+-----------------------------------------------------+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
@@ -53,6 +94,59 @@ explain analyze
|_|_| Total rows: 4_|
+-+-+-+
select last_value(ts order by ts) from t;
+-------------------------------------------------+
| last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+-------------------------------------------------+
| 1970-01-01T00:00:00.008 |
+-------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select last_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[]], aggr=[[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select last_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":1, "files":0, "file_ranges":0}, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
drop table t;
Affected Rows: 0

View File

@@ -16,6 +16,25 @@ insert into t values
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
@@ -32,4 +51,23 @@ explain analyze
from t
group by host;
drop table t;
select last_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select last_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select last_value(ts order by ts) from t;
drop table t;

View File

@@ -0,0 +1,821 @@
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
) with (append_mode='true');
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
admin flush_table('t');
+------------------------+
| ADMIN flush_table('t') |
+------------------------+
| 0 |
+------------------------+
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
-- repeat the query again, ref: https://github.com/GreptimeTeam/greptimedb/issues/4650
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+---------------------------------------------------+-----------------------------------------------------+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":0, "files":1, "file_ranges":1}, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select last_value(ts order by ts) from t;
+-------------------------------------------------+
| last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+-------------------------------------------------+
| 1970-01-01T00:00:00.008 |
+-------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select last_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeScan [is_placeholder=false, remote_input=[_|
|_| Projection: last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[]], aggr=[[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select last_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":{"count":1, "mem_ranges":0, "files":1, "file_ranges":1}, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
drop table t;
Affected Rows: 0
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
);
Affected Rows: 0
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
Affected Rows: 9
select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
+--------------+-----------------------------------------------------+--------------------------------------------------+
| ordered_host | last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] |
+--------------+-----------------------------------------------------+--------------------------------------------------+
| a | 🌓 | 7.0 |
| b | 🌒 | 6.0 |
| c | 🌔 | 8.0 |
| d | 🌕 | 9.0 |
+--------------+-----------------------------------------------------+--------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: ordered_host ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: ordered_host ASC NULLS LAST_|
|_|_Projection: last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] AS ordered_host, last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t.host]], aggr=[[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 1_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 2_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@1 as host], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.not_pk) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select last_value(ts order by ts) from t;
+-------------------------------------------------+
| last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] |
+-------------------------------------------------+
| 1970-01-01T00:00:00.008 |
+-------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select last_value(ts order by ts) from t;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__last_value_merge(__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]) AS last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]]]_|
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select last_value(ts order by ts) from t;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+--------------+--------------------------------------------------+-------------------------------------------------+-------------------------+
| ordered_host | last_value(t.val) ORDER BY [t.ts ASC NULLS LAST] | last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST] | time_window |
+--------------+--------------------------------------------------+-------------------------------------------------+-------------------------+
| a | 5.0 | 1970-01-01T00:00:00.004 | 1970-01-01T00:00:00 |
| d | 9.0 | 1970-01-01T00:00:00.008 | 1970-01-01T00:00:00.005 |
+--------------+--------------------------------------------------+-------------------------------------------------+-------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST, ordered_host ASC NULLS LAST_|
|_|_Projection: last_value(t.host) ORDER BY [t.ts ASC NULLS LAST] AS ordered_host, last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts) AS time_window_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("5 milliseconds"),t.ts)]], aggr=[[__last_value_merge(__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST]) AS last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_merge(__last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST]) AS last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_merge(__last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]) AS last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("5 milliseconds") AS Interval(MonthDayNano)), t.ts)]], aggr=[[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]]]_|
|_|_TableScan: t_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts)@0 as time_window]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST]@1 as ordered_host, last_value(t.val) ORDER BY [t.ts ASC NULLS LAST]@2 as last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]@3 as last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t.ts)@0 as time_window] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[last_value(t.host) ORDER BY [t.ts ASC NULLS LAST], last_value(t.val) ORDER BY [t.ts ASC NULLS LAST], last_value(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t.ts)@0 as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@0) as date_bin(Utf8("5 milliseconds"),t.ts)], aggr=[__last_value_state(t.host) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.val) ORDER BY [t.ts ASC NULLS LAST], __last_value_state(t.ts) ORDER BY [t.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 2_|
+-+-+-+
drop table t;
Affected Rows: 0
CREATE TABLE phy (ts timestamp time index, val double, host string primary key)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
) engine=metric with ("physical_metric_table" = "");
Affected Rows: 0
CREATE TABLE t1 (ts timestamp time index, val double, host string primary key) engine = metric with ("on_physical_table" = "phy");
Affected Rows: 0
insert into
t1(ts, val, host)
values
(0, 1.0, 'a'),
(1, 2.0, 'b'),
(2, 3.0, 'a'),
(3, 4.0, 'c'),
(4, 5.0, 'a'),
(5, 6.0, 'b'),
(6, 7.0, 'a'),
(7, 8.0, 'c'),
(8, 9.0, 'd');
Affected Rows: 9
select last_value(ts order by ts) from t1;
+---------------------------------------------------+
| last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST] |
+---------------------------------------------------+
| 1970-01-01T00:00:00.008 |
+---------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select last_value(ts order by ts) from t1;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Aggregate: groupBy=[[]], aggr=[[__last_value_merge(__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]) AS last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[]], aggr=[[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]]_|
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | AggregateExec: mode=Final, gby=[], aggr=[last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CoalescePartitionsExec_|
|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select last_value(ts order by ts) from t1;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=Final, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalescePartitionsExec REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[], aggr=[__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 1_|
+-+-+-+
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
+--------------+----------------------------------------------------+
| ordered_host | last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST] |
+--------------+----------------------------------------------------+
| a | 7.0 |
| b | 6.0 |
| c | 8.0 |
| d | 9.0 |
+--------------+----------------------------------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| MergeSort: ordered_host ASC NULLS LAST_|
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Sort: ordered_host ASC NULLS LAST_|
|_|_Projection: last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST] AS ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]_|
|_|_Aggregate: groupBy=[[t1.host]], aggr=[[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST]_|
|_|_CooperativeExec_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 1_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
| 1_| 2_|_SortPreservingMergeExec: [ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[host@0 as host], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED, "selector":"LastRow" REDACTED
|_|_|_|
|_|_| Total rows: 4_|
+-+-+-+
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+--------------+----------------------------------------------------+---------------------------------------------------+-------------------------+
| ordered_host | last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST] | last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST] | time_window |
+--------------+----------------------------------------------------+---------------------------------------------------+-------------------------+
| a | 5.0 | 1970-01-01T00:00:00.004 | 1970-01-01T00:00:00 |
| d | 9.0 | 1970-01-01T00:00:00.008 | 1970-01-01T00:00:00.005 |
+--------------+----------------------------------------------------+---------------------------------------------------+-------------------------+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+-+-+
| plan_type_| plan_|
+-+-+
| logical_plan_| Sort: time_window ASC NULLS LAST, ordered_host ASC NULLS LAST_|
|_|_Projection: last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST] AS ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts) AS time_window_|
|_|_Aggregate: groupBy=[[date_bin(Utf8("5 milliseconds"),t1.ts)]], aggr=[[__last_value_merge(__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST]) AS last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_merge(__last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST]) AS last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_merge(__last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]) AS last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]] |
|_|_MergeScan [is_placeholder=false, remote_input=[_|
|_| Aggregate: groupBy=[[date_bin(CAST(Utf8("5 milliseconds") AS Interval(MonthDayNano)), t1.ts)]], aggr=[[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]]_|
|_|_TableScan: t1_|
|_| ]]_|
| physical_plan | SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST]_|
|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]@3 as last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts)@0 as time_window]_|
|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CoalesceBatchesExec: target_batch_size=8192_|
|_|_RepartitionExec: REDACTED
|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]]_|
|_|_CooperativeExec_|
|_|_MergeScanExec: REDACTED
|_|_|
+-+-+
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
+-+-+-+
| stage | node | plan_|
+-+-+-+
| 0_| 0_|_SortPreservingMergeExec: [time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST] REDACTED
|_|_|_SortExec: expr=[time_window@3 ASC NULLS LAST, ordered_host@0 ASC NULLS LAST], preserve_REDACTED
|_|_|_ProjectionExec: expr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST]@1 as ordered_host, last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST]@2 as last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]@3 as last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST], date_bin(Utf8("5 milliseconds"),t1.ts)@0 as time_window] REDACTED
|_|_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[last_value(t1.host) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.val) ORDER BY [t1.ts ASC NULLS LAST], last_value(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_MergeScanExec: REDACTED
|_|_|_|
| 1_| 0_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 1_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
| 1_| 2_|_AggregateExec: mode=FinalPartitioned, gby=[date_bin(Utf8("5 milliseconds"),t1.ts)@0 as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CoalesceBatchesExec: target_batch_size=8192 REDACTED
|_|_|_RepartitionExec: REDACTED
|_|_|_AggregateExec: mode=Partial, gby=[date_bin(IntervalMonthDayNano { months: 0, days: 0, nanoseconds: 5000000 }, ts@1) as date_bin(Utf8("5 milliseconds"),t1.ts)], aggr=[__last_value_state(t1.host) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.val) ORDER BY [t1.ts ASC NULLS LAST], __last_value_state(t1.ts) ORDER BY [t1.ts ASC NULLS LAST]] REDACTED
|_|_|_CooperativeExec REDACTED
|_|_|_SeqScan: region=REDACTED, "partition_count":REDACTED REDACTED
|_|_|_|
|_|_| Total rows: 2_|
+-+-+-+
drop table t1;
Affected Rows: 0
drop table phy;
Affected Rows: 0

View File

@@ -0,0 +1,344 @@
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
) with (append_mode='true');
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
admin flush_table('t');
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
-- repeat the query again, ref: https://github.com/GreptimeTeam/greptimedb/issues/4650
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select
last_value(host order by ts),
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host;
select last_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select last_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
explain analyze
select last_value(ts order by ts) from t;
drop table t;
create table t (
ts timestamp time index,
host string primary key,
not_pk string,
val double,
)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
);
insert into t values
(0, 'a', '🌕', 1.0),
(1, 'b', '🌖', 2.0),
(2, 'a', '🌗', 3.0),
(3, 'c', '🌘', 4.0),
(4, 'a', '🌑', 5.0),
(5, 'b', '🌒', 6.0),
(6, 'a', '🌓', 7.0),
(7, 'c', '🌔', 8.0),
(8, 'd', '🌕', 9.0);
select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(not_pk order by ts),
last_value(val order by ts)
from t
group by host
order by ordered_host;
select last_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain select last_value(ts order by ts) from t;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select last_value(ts order by ts) from t;
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t
group by time_window
order by time_window, ordered_host;
drop table t;
CREATE TABLE phy (ts timestamp time index, val double, host string primary key)
PARTITION ON COLUMNS (host) (
host < 'b',
host >= 'b' AND host < 'd',
host >= 'd'
) engine=metric with ("physical_metric_table" = "");
CREATE TABLE t1 (ts timestamp time index, val double, host string primary key) engine = metric with ("on_physical_table" = "phy");
insert into
t1(ts, val, host)
values
(0, 1.0, 'a'),
(1, 2.0, 'b'),
(2, 3.0, 'a'),
(3, 4.0, 'c'),
(4, 5.0, 'a'),
(5, 6.0, 'b'),
(6, 7.0, 'a'),
(7, 8.0, 'c'),
(8, 9.0, 'd');
select last_value(ts order by ts) from t1;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select last_value(ts order by ts) from t1;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select last_value(ts order by ts) from t1;
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts)
from t1
group by host
order by ordered_host;
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
explain
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
-- SQLNESS REPLACE (-+) -
-- SQLNESS REPLACE (\s\s+) _
-- SQLNESS REPLACE (elapsed_compute.*) REDACTED
-- SQLNESS REPLACE (peers.*) REDACTED
-- SQLNESS REPLACE (RoundRobinBatch.*) REDACTED
-- SQLNESS REPLACE (metrics.*) REDACTED
-- SQLNESS REPLACE (partitioning.*) REDACTED
-- SQLNESS REPLACE region=\d+\(\d+,\s+\d+\) region=REDACTED
-- might write to different partitions
-- SQLNESS REPLACE "partition_count":\{(.*?)\} "partition_count":REDACTED
explain analyze
select
last_value(host order by ts) as ordered_host,
last_value(val order by ts),
last_value(ts order by ts),
date_bin('5ms'::INTERVAL, ts) as time_window
from t1
group by time_window
order by time_window, ordered_host;
drop table t1;
drop table phy;