clickhouse optimize_read_in_order 劣化

784 阅读1分钟

在查询 clickhouse 时,当同时使用 limit 和 order by 时,如果 order by 的顺序与表顺序一致, 则可以加速查询。

但是 optimize_read_in_order 在某些情况下会导致性能裂化。

建表语句:

create table test (
`a` string,
b `string`,
d `string`,
index_d)
ENGINE = MergeTree order by (a, b)

使用普通磁盘测试, ssd 太快了测不出来,冷热分离的时候就有坑了。

optimize_read_in_order 加速的查询

按前缀主键排序:

order by prefix primary key

查询语句:

select * from test order by a limit 1

倒序逆序无影响。

optimize_read_in_order 可能无效的情况

按部分主键过滤并按剩余主键排序:

filter with prefix primary key and order by suffix primary key

查询语句:

select * from test where a = ? order by b limit 1

当 clickhouse 版本较低(21.8.3, 阿里云最新 clickhouse)时无效, 最新版 clickhouse 有效。

前缀主键和后缀主键加起来必须构成完整的主键,

optimize_read_in_order 劣化的查询

当查询条件上有索引时: github.com/ClickHouse/…

select * from test where d = ? order by a limit 1
  • optimize_read_in_order = true。 sql 会先读取数据,然后再进行过滤,这个过程不会使用 d 的索引。
  • optimize_read_in_order = false。sql 会首先使用 d 的索引过滤出所有符合条件的数据,然后再排序。

一些奇怪的情况

即使是最简单的查询, 如果排序键的顺序与主键顺序不一致,也有可能导致劣化: github.com/ClickHouse/…

select * from test where b = ? order by a desc limit 1

这种情况下,建议修改表主键排序顺序:

create table test (
`a` string,
b `string`,
d `string`,
index_d)
ENGINE = MergeTree order by (-a, b)

然后使用 -a asc 的方式,来达到 a desc 的排序。

select * from test where b = ? order by -a limit 1