为啥 maxMerge() 给出的结果与 sumMerge() 的 max() 不同?

Posted

技术标签:

【中文标题】为啥 maxMerge() 给出的结果与 sumMerge() 的 max() 不同?【英文标题】:Why maxMerge() gives different results than max() of sumMerge()?为什么 maxMerge() 给出的结果与 sumMerge() 的 max() 不同? 【发布时间】:2021-08-11 17:05:03 【问题描述】:

重点是在每个周期获得峰值(例如 5m 个峰值)以获取累积值。所以需要对每个周期求和,然后可以在这些总和中找到峰值(最大值)。 (select max(v) from (select sum(v) from t group by a1, a2))


我有一个基表t

数据被插入t,考虑两个属性(时间t1和一些字符串a2)和一个数值。

价值会累积,因此需要将其相加以获得特定时期的总交易量。插入行示例:

t1     | a2 | v
----------------
date1  | b  | 1
date2  | c  | 20

我使用 MV 来计算 sumState(),然后使用 sumMerge()max() 得到峰值。

我只需要最大值,所以我想知道我可以直接使用maxState()


这就是我现在要做的:我使用计算 5m 总和的 MV,并从中读取 max()

CREATE TABLE IF NOT EXISTS sums_table ON CLUSTER 'cluster' (
    t1              DateTime,
    a2              String,
    v               AggregateFunction(sum, UInt32)
)
ENGINE = ReplicatedAggregatingMergeTree(
    '...',
    'replica'
)
    PARTITION BY toDate(t1) 
    ORDER BY (a2, t1)
    PRIMARY KEY (a2);
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_a
    ON CLUSTER 'cluster'
    TO sums_table
AS
SELECT toStartOfFiveMinute(t1) AS t1, a2,
    sumState(toUInt32(v)) AS v
FROM t
GROUP BY t1, a2

从中我可以读取 a2 的最大 5m 总和

SELECT
    a2,
    max(sum) AS max
FROM (
    SELECT
        t1,
        a2,
        sumMerge(v) AS sum
    FROM sums_table
    WHERE t1 BETWEEN :fromDateTime AND :toDateTime
    GROUP BY t1, a2
)
GROUP BY a2
ORDER BY max DESC

效果很好。


所以我想使用maxStatemaxMerge() 来达到同样的效果:

CREATE TABLE IF NOT EXISTS max_table ON CLUSTER 'cluster' (
    t1              DateTime,
    a2              String,
    max_v           AggregateFunction(max, UInt32)
)
ENGINE = ReplicatedAggregatingMergeTree(
    '...',
    'replica'
)
    PARTITION BY toDate(t1) 
    ORDER BY (a2, t1)
    PRIMARY KEY (a2)
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_b
    ON CLUSTER 'cluster'
    TO max_table
AS
SELECT
    t1,
    a2
    maxState(v) AS max_v
FROM (
    SELECT
        toStartOfFiveMinute(t1) AS t1,
        a2,
        toUInt32(sum(v)) AS v
    FROM t
    GROUP BY t1, a2
)
GROUP BY t1, a2

我想如果我每次得到一个最大值 (t1) 和 a2,然后选择每个 a2 中的最大值,我会得到每个 a2 的最大值,但是使用这个我得到完全不同的最大值查询与上述总和的最大值相比。

SELECT
    a2,
    max(max) AS max
FROM (
    SELECT
        t1,
        a2,
        maxMerge(v) AS max
    FROM max_table
    WHERE t1 BETWEEN :fromDateTime AND :toDateTime
    GROUP BY t1, a2
) maxs_per_time_and_a2
GROUP BY a2

我做错了什么?是不是我弄错了MV?是否可以将maxStatemaxMerge 用于2+ 属性来计算更长时期内的最大值,比如年份?

【问题讨论】:

【参考方案1】:
SELECT
    t1,
    a2
    maxState(v) AS max_v
FROM (
    SELECT
        toStartOfFiveMinute(t1) AS t1,
        a2,
        toUInt32(sum(v)) AS v
    FROM t
    GROUP BY t1, a2
)
GROUP BY t1, a2

这是不正确的。而且不可能。 因为 MV 是一个插入触发器。它从不读取 REAL 表 t。 您正在从插入缓冲区中的行总和中获得最大值。

如果您使用v=10 插入 1 行。您将得到 max_v = 10。MatView 不“知道”先前的插入添加了一些行,它们的总和不被考虑在内。

【讨论】:

啊,所以使用maxState 从源表中聚合最大值是不可行的,对吧?或者任何聚合函数基本上都不能与 MV 一起使用,而 MV 则用于数据过滤。我只能想象求和 sumMerges ? 没有。只有具有不同聚合函数的双重聚合是不可行的。 maxState 在 MV 中完美运行。

以上是关于为啥 maxMerge() 给出的结果与 sumMerge() 的 max() 不同?的主要内容,如果未能解决你的问题,请参考以下文章

Python append() 与列表上的 + 运算符,为啥这些会给出不同的结果?

Python append() 与列表上的 + 运算符,为啥这些会给出不同的结果?

为啥这个 MySQL 存储函数给出的结果与在查询中进行计算不同?

为啥 == 与 Integer.valueOf(String) 的比较对 127 和 128 给出不同的结果?

为啥我的 k-means 收敛条件给出的结果与 sklearn 不同?

为啥 gbm() 在这个最小示例中给出的结果与 h2o.gbm() 不同?