【问题标题】:Optimising fetching multiple latest values for the last() and GROUP BY in TimescaleDB优化在 TimescaleDB 中为 last() 和 GROUP BY 获取多个最新值
【发布时间】:2021-11-21 07:50:54
【问题描述】:

我有一个查询,它在 TimescaleDb 中获取多个资产之前 24 小时的最新价格和价格。然后我的应用程序继续计算应用程序端价格变化的百分比。因为可能没有任何交易,时间桶的最新价格可能不可用,所以我需要填补空白“如果这个时间桶没有价值,那么取之前的价值”。然后价格变化作为非规范化值存储在普通 PostgreSQL 表中,以便在普通 PostgreSQL 查询中更快、更有用,查询类似于JOIN latest_price

查询在 TimescaleDB 连续聚合视图上执行。

我正在使用last(),并且我知道获取最新值是subject to discussion before。但是,在我的问题中,有一种特殊情况是一次获取多个最新和接近最新的值。

目前,我的价格和 24 小时价格增量计算方法使用两个 last() 查询,在生产中计时 100 秒。然而,类似的参考查询不使用last(),但使用天真的GROUP BY,只需1 秒。

优化需要从 TimescaleDB 为一组项目获取多个最新值,然后对它们执行计算的查询的最佳方法是什么?子查询会更快吗?示例子查询是什么样的?

在更新candle_ohlcvx_aggregate_1h 时创建一个存储最新值的触发器是否有意义?触发器是否适用于连续聚合视图?这个触发器是什么样子的?

我的价格计算查询:


        -- Get the latest price
        SELECT
            pair_id,
            last(close, bucket) as last_close
        FROM candle_ohlcvx_aggregate_15m
        WHERE (bucket < :now_ts) AND (pair_id IN :pair_ids) 
        GROUP BY pair_id;

        -- Get the latest price 24h ago
        SELECT
            pair_id,
            last(close, bucket) as last_close
        FROM candle_ohlcvx_aggregate_15m
        WHERE (bucket < (:now_ts - INTERVAL '1 DAY')) AND (pair_id IN :pair_ids) 
        GROUP BY pair_id;

我的参考查询没有最后一个时钟 1 秒挂钟时间 - 使用每小时存储桶计算一天的音量,但不使用 last() 填充最后一个值使其快速:

SELECT
            pair_id, SUM(buy_volume) + SUM(sell_volume) as vol
        FROM candle_ohlcvx_aggregate_1h
        WHERE (bucket >= :now_ts - INTERVAL '1 DAY') AND (bucket < :now_ts) AND (pair_id IN :pair_ids)
        GROUP BY pair_id
        ORDER BY pair_id ASC;
    """

【问题讨论】:

    标签: timescaledb


    【解决方案1】:

    这两个查询都将扫描整个连续聚合。通过使用我们独特的优化,可以在基表(而不是连续聚合)上完成此查询:https://blog.timescale.com/blog/how-we-made-distinct-queries-up-to-8000x-faster-on-postgresql/

     SELECT DISTINCT ON (pair_id)
                *
                
            FROM base
            WHERE (ts < :now_ts) AND (pair_id IN :pair_ids) 
            ORDER BY pair_id, ts DESC ;
    
    -- and 
    
     SELECT DISTINCT ON (pair_id)
                *
                
            FROM base
            WHERE (ts < :now_ts - INTERVAL '1 DAY') AND (pair_id IN :pair_ids) 
            ORDER BY pair_id, ts DESC ;
    
    

    您需要在(pair_id, ts) 上有一个索引才能有效。我们正在寻找在连续聚合上提高效率的方法,但目前独特的优化并不能真正对它们起作用,因为它们在后台进行了分组。

    另一种选择是从您的对表之类的东西中执行横向子查询(假设存在一个,您也可以在子查询或其他东西中取消嵌套数组对):

    
    SELECT p.pair_id, 
           c.close
    FROM pairs p, LATERAL (SELECT close FROM  candle_ohlcvx_aggregate_15m ca WHERE ca.bucket < :now_ts AND ca.pair_id = p.pair_id ORDER BY ca.bucket DESC LIMIT 1) c 
            WHERE   (p.pair_id IN :pair_ids);
    
    SELECT p.pair_id, 
           c.close
    FROM pairs p, LATERAL (SELECT close FROM  candle_ohlcvx_aggregate_15m ca WHERE ca.bucket < :now_ts - INTERVAL '1 hour' AND ca.pair_id = p.pair_id ORDER BY ca.bucket DESC LIMIT 1) c 
            WHERE   (p.pair_id IN :pair_ids);
    

    这可能会稍微降低效率,但我认为至少应该避免扫描整个连续聚合。

    【讨论】:

    • 大卫你好!感谢您的出色回答。我会试试这个并报告结果。请继续在 StackOverflow 上保持出色的工作和出色的回复。
    猜你喜欢
    • 2011-04-24
    • 2012-11-17
    • 1970-01-01
    • 2017-09-03
    • 2021-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-24
    相关资源
    最近更新 更多