【问题标题】:Clickhouse select last record without max() on all tableClickhouse 选择所有表上没有 max() 的最后一条记录
【发布时间】:2019-08-31 15:54:25
【问题描述】:

表中有数十亿行用于 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(75.121 万行/秒,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() 查找最后一个元素

【问题讨论】:

    标签: sql clickhouse


    【解决方案1】:

    实际上是因为它仍然需要使用相同的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;
    

    【讨论】:

      【解决方案2】:

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

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

      你可以试试这个(根据你的需要修改):

      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
      

      【讨论】:

      • 好的,那么我的变体可能会以相同的速度工作。它只会让您从最大行中获取值作为奖励
      猜你喜欢
      • 2018-01-26
      • 1970-01-01
      • 2017-04-11
      • 1970-01-01
      • 2015-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多