【问题标题】:Reusing the same moving window for multiple window functions为多个窗口功能重用同一个移动窗口
【发布时间】:2019-09-06 01:55:23
【问题描述】:

我在 Postgres 数据库中有一个数字表,我正在尝试为每一行计算前 3 行和后 3 行的范围(最大值-最小值)。 给定一个测试表:

CREATE TABLE test_table AS (
SELECT
    generate_series(1,100) id,
    random()*generate_series(1,100) val
);

这可以通过以下查询来完成:

SELECT
    id,
    MAX(val) OVER (
        ORDER BY id
        ROWS
            BETWEEN 3 PRECEDING
            AND 3 FOLLOWING
    ) - 
    MIN(val) OVER (
        ORDER BY id
        ROWS
            BETWEEN 3 PRECEDING
            AND 3 FOLLOWING
    ) val_range
FROM test_table;

但是OVER 子句是重复的。有没有办法改进查询并删除重复项?重复会影响性能吗?如果我想为每个 id 计算其他聚合,我应该如何处理移动窗口?

我想出了以下查询来重用窗口,但我不确定这是否是最佳方法。

WITH
windowed AS (
SELECT
    id,
    UNNEST(ARRAY_AGG(val) OVER (
        ORDER BY id
        ROWS
            BETWEEN 3 PRECEDING
            AND 3 FOLLOWING
    )) val
FROM test_table
)
SELECT
    id,
    MAX(val)-MIN(val) val_range,
    AVG(val) val_mean,
    STDDEV(val) val_stddev
FROM windowed
GROUP BY id
ORDER BY id;

【问题讨论】:

    标签: sql postgresql window-functions


    【解决方案1】:

    您可以使用WINDOW clause 来缩短您的代码:

    SELECT id
         , MAX(val) OVER w - 
           MIN(val) OVER w AS val_range
    FROM   test_table
    WINDOW w AS (ORDER BY id ROWS BETWEEN 3 PRECEDING AND 3 FOLLOWING);
    

    但这几乎不会影响性能。如果您重复拼写,Postgres 将重用窗口框架。 The manual:

    当使用多个窗口函数时,所有窗口函数 具有语法等效的 PARTITION BY 和 ORDER BY 子句 在他们的窗口定义保证在一个单一的评估 传递数据。

    相关:

    【讨论】:

    • 有道理! WINDOW a 应该是 WINDOW w 吗?
    • 使用SELECT...WINDOW... 只是语法糖通常是真的吗?它甚至可以提高性能吗?
    • @LondonRob:是的。 WINDOW 子句只是 Postgres 中的一个“便利功能”,因此您可以在窗口函数的多个 OVER 子句中重用窗口定义。我添加了手册中的引用。
    • 谢谢,这实际上是关于windows的一个重要的额外信息:你不必担心多次指定同一个window,查询规划器会全部排序,只计算每个window一次!
    猜你喜欢
    • 2021-10-22
    • 1970-01-01
    • 2023-03-24
    • 2013-10-11
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多