Clickhouse选择所有表上没有max()的最后一条记录

时间:2019-04-10 08:45:36

标签: sql clickhouse

我在表中有几百亿行用于4k可变参数,我需要获取其中500个的最后一个值 我的表按天和按参数ID排序,因此我只需要查找具有所需ID的最后一条记录

SELECT max(time)
FROM obj_ntgres.param_values_history
PREWHERE param_id = 4171

工作缓慢: 耗时:0.437秒。已处理256万行,5.21 MB(587万行/秒,11.92 MB /秒)

SELECT *
FROM obj_ntgres.param_values_history
PREWHERE param_id = 4171
ORDER BY time DESC
LIMIT 1

较慢: 设置1行。耗时:3.413秒。已处理256万行,5.45 MB(751.21万行/秒,1.60 MB /秒)

CREATE TABLE obj_ntgres.param_values_history (

  time DateTime,

  param_id UInt16,

  param_value Float32,

  param_value_quality Decimal(1, 0),

  msec Decimal(3, 0)

) ENGINE = MergeTree PARTITION BY toStartOfDay(time)

ORDER BY

  param_id SETTINGS index_granularity = 8192

也许您有一些想法使其更快?

我的意思是:在所有表上不使用max()查找最后一个元素

2 个答案:

答案 0 :(得分:2)

实际上是它仍然需要使用相同的param_id扫描大量数据的原因。

几乎没有办法。在开始的所有情况下,都需要向表排序键添加time列:

    CREATE TABLE param_values_history (
      time DateTime,
      param_id UInt16,
      param_value Float32,
      param_value_quality Decimal(1, 0),
      msec Decimal(3, 0)
    ) ENGINE = MergeTree PARTITION BY toStartOfDay(time)
    ORDER BY
      (param_id,time) SETTINGS index_granularity = 8192

此后-如果您的数据是时间对齐的,即,如果您确切地知道所有500个参数在过去的几秒钟/分钟内都有某个值,则只需添加一个类似AND time > now() - INTERVAL 10 MINUTES的过滤器,它将工作真的非常快(无需扫描很多行)。

如果您的某些参数没有常规活动,则情况会更糟。

在这种情况下,最快的方法是通过实例化视图(甚至是整个最后一行)缓存每个参数的最后时间。像这样:

CREATE MATERIALIZED VIEW last_positions
 Engine=ReplacingMergeTree(max_time)
ORDER BY param_id
PARTITION BY tuple()
AS SELECT param_id, max(time) as max_time
FROM param_values_history
GROUP BY param_id;

SELECT * FROM param_values_history PREWHERE (param_id,time) IN (SELECT param_id, max(max_time) FROM last_positions GROUP BY param_id);

或者:MV中收集的最后一行全部

CREATE MATERIALIZED VIEW last_positions
 Engine=ReplacingMergeTree(max_time)
ORDER BY param_id
PARTITION BY tuple()
AS SELECT param_id,
   argMax(param_value, time) as _param_value, 
   argMax(param_value_quality, time) as _param_value_quality, 
   argMax(param_value, msec) as _msec, 
   max(time) as max_time
FROM param_values_history
GROUP BY param_id;

SELECT * FROM last_positions FINAL;

答案 1 :(得分:0)

我不明白您所说的“工作不好”的意思。但是如果问题是

  

选择带有特定位置的最后一条记录

您可以尝试一下(根据您的需要进行修改):

SELECT 
    max((time, param_value, param_value_quality, msec)) AS result,
    result.2 AS param_value,
    result.3 AS param_value_quality
FROM obj_ntgres.param_values_history
PREWHERE param_id = 4171