clickhouse 有本地表和分布式表,向分布式表的查询会下发到每个本地表去执行。
比如:
select * from table limit 20
该查询,会在 clickhouse 集群上的每个节点运行并返回数据。
如果已经返回了二十条,那么其他节点的查询就会被 cancel。
但:
select * from table order by timestamp desc limit 20
查询需要等所有节点返回后才能执行完成。
查询总时间取决于最慢节点的执行时间。
由于 clickhouse 的 bug,向分布式节点的 order by -toUnixTimestamp(timestamp) 会被转换成本地表上的 order by time desc github.com/ClickHouse/…
而 clickhouse 的另一个 bug,会导致 order by time desc 没有 order by time asc 快,其中主键按 time 排序(即使对 24.x 的 clickhouse 依然生效)
fiddle.clickhouse.com/7b3ab627-b3…
因此我们直接向每个节点查询:
select * from table order by -toUnixTimestamp(timestamp) limit 20
通过最新的 clickhouse-go 客户端。
我们可以向每个子节点并行发起查询,若数据已足够,就终止其他并行的查询。
查询总时间取决于最快节点的执行时间。
ctx, cancel := context.WithCancel(ctx)
for i := 0; i < len(conns); i++ {
go func(i int) {
conn := conns[i]
conn.Query(ctx, query)
if enough data {
// 终止其他并发查询
cancel()
return
}
}(i)
}
这样数据不是全局有序的,但是很快。