ClickHouse - SELECT 行数据太慢

ClickHouse - SELECT row of data is too slow

我们项目中出现以下问题,无法解决。 我们有大量的日志数据,我们从 MongoDB.

转到 ClickHouse

我们的table是这样创建的:

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,toDateTime(ts),context,level,event,data 
FROM logs 
WHERE device_id = 'some_uuid'

这是结果 耗时:7.994 秒。 每 500 行 130000+

太慢了。

似乎 CH 处理了 table 中的所有行。 CH有什么问题需要提高速度吗?

MongoDB 上的相同实现需要 200-500 毫秒 max

叶戈尔!当您提到“我们从 MongoDB 转到 ClickHouse”时,您的意思是您从 MongoDB 切换到 ClickHouse 来存储您的数据吗?或者您以某种方式连接到 ClickHouse,从 MongoDB 到您所指的 运行 查询?

我不确定你是如何摄取数据的,但让我们专注于阅读部分。

对于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,toDateTime(ts),context,level,event,data 
FROM logs 
WHERE device_id = 'some_uuid' AND week = '2021-07-05';

AFAIK,除非您指定了确切的分区格式,否则 CH 将为您的 CREATE TABLE 语句使用按月分区(即 toYYYYMM())。您可以通过查看 system.parts table:

来检查
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