问题描述
在我们的项目中出现了以下问题,我们无法解决。 我们有大量日志数据,我们从 MongoDB 转到 ClickHouse。
我们的表是这样创建的:
CREATE TABLE IF NOT EXISTS logs ON CLUSTER default (
raw String,ts DateTime64(6) MATERIALIZED toDateTime64(JSONExtractString(raw,'date_time'),6),device_id String MATERIALIZED JSONExtractString(raw,'device_id'),level Int8 MATERIALIZED JSONExtractInt(raw,'level'),context String MATERIALIZED JSONExtractString(raw,'context'),event String MATERIALIZED JSONExtractString(raw,'event'),event_code String MATERIALIZED JSONExtractInt(raw,'event_code'),data String MATERIALIZED JSONExtractRaw(raw,'data'),date Date DEFAULT toDate(ts),week Date DEFAULT toMonday(ts)
)
ENGINE ReplicatedReplacingMergeTree()
ORDER BY (device_id,ts)
PARTITION BY week
我正在运行这样的查询
SELECT device_id,toDateTime(ts),context,level,event,data
FROM logs
WHERE device_id = 'some_uuid'
ORDER BY ts DESC
LIMIT 10
OFFSET 0;
这是结果集 10 行。 已用时间:6.23 秒。
第二个没有顺序、限制和偏移量:
SELECT device_id,data
FROM logs
WHERE device_id = 'some_uuid'
这是结果 Elapsed: 7.994 sec. 对于每 500 行 130000+
太慢了。
似乎 CH 处理了表中的所有行。有什么问题,需要提高CH的速度吗?
MongoDB 上的相同实现需要 200-500 毫秒 最大
解决方法
叶戈尔!当您提到“我们从 MongoDB 转到 ClickHouse”时,您的意思是您从 MongoDB 切换到 ClickHouse 来存储数据吗?或者您以某种方式从 MongoDB 连接到 ClickHouse 以运行您所指的查询?
我不确定你是如何摄取数据的,但让我们专注于阅读部分。
对于 MergeTree 家族,ClickHouse 分部分写入数据。因此,将时间戳作为 where 子句的一部分至关重要,因此 ClickHouse 可以确定您要读取的部分并跳过您不需要的大部分数据。否则,它将扫描所有数据。
我想这些查询会更快地进行扫描:
SELECT device_id,toDateTime(ts),context,level,event,data
FROM logs
WHERE device_id = 'some_uuid' AND week = '2021-07-05'
ORDER BY ts DESC
LIMIT 10
OFFSET 0;
SELECT device_id,data
FROM logs
WHERE device_id = 'some_uuid' AND week = '2021-07-05';
AFAIK,除非您指定了确切的分区格式,否则 CH 将对您的 toYYYYMM()
语句使用按月分区(即 CREATE TABLE
)。您可以通过查看 system.parts
表来检查:
SELECT
partition,name,active
FROM system.parts
WHERE table = 'logs'
所以,如果你想按周存储数据,我想分区可能是这样的
...
ORDER BY (device_id,ts)
PARTITION BY toMonday(week)
这也是一条很好的信息:Using Partitions and Primary keys in queries