clickhouse 查询提前终止

174 阅读1分钟

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)
}

这样数据不是全局有序的,但是很快。