SQL Server:使用具有相同 OVER 子句的多个聚合/分析函数?

Posted

技术标签:

【中文标题】SQL Server:使用具有相同 OVER 子句的多个聚合/分析函数?【英文标题】:SQL Server: Use multiple aggregate/analytic functions with same OVER clause? 【发布时间】:2021-06-29 12:02:48 【问题描述】:

以下 SQL Server 查询:

SELECT DISTINCT NodeID, dateadd(hour, datediff(hour, 0, Timestamp), 0) as dt_hour
,AVG(Availability)  
    OVER (PARTITION BY NodeID, dateadd(hour, datediff(hour, 0, Timestamp), 0)) AS avg  
,PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY Availability)  
    OVER (PARTITION BY NodeID, dateadd(hour, datediff(hour, 0, Timestamp), 0)) AS perc90  
,MAX(Availability)  
    OVER (PARTITION BY NodeID, dateadd(hour, datediff(hour, 0, Timestamp), 0)) AS max  
FROM InterfaceAvailability_CS_Detail_hist
order by NodeID, dt_hour;

运行时间大约是这个的 3 倍:

SELECT DISTINCT NodeID, dateadd(hour, datediff(hour, 0, Timestamp), 0) as dt_hour
,PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY Availability)  
    OVER (PARTITION BY NodeID, dateadd(hour, datediff(hour, 0, Timestamp), 0)) AS perc90  
FROM InterfaceAvailability_CS_Detail_hist
order by NodeID, dt_hour;

我怀疑它对每个聚合(AVGPERCENTILE_CONTMAX)都进行了冗余分区。有没有办法只编写一次OVER 子句并将其应用于每个聚合?

【问题讨论】:

使用OVER 子句的函数不是聚合函数... Edit问题并提供minimal reproducible example,即表和索引的CREATE语句(粘贴文本,不要使用图像), INSERT 用于示例数据 (dito) 的语句、表格文本格式的示例数据的期望结果以及您的查询的当前计划。 "OVER 子句可能跟在所有聚合函数后面" - https://docs.microsoft.com/en-us/sql/t-sql/functions/aggregate-functions-transact-sql @MarkPundurs,使用多余的PARTITION BY 子句不一定会导致执行多余的工作。你能分享你的查询计划吗? 几乎可以肯定是DISTINCT 给您带来了问题。为什么它首先存在,从外观上看,你真的想要一个具有正常聚合的GROUP BY。完全相同的PARTITION BY 多次几乎肯定不会多次计算分区,只有实际函数会 【参考方案1】:

如果没有看到查询计划,很难知道发生了什么,但我的猜测是,通过在 parititon by 子句中使用标量函数,您限制了 sql server 可以做哪些优化查询。

我尝试了一个类似的查询,并通过使用 CTE 为 dt_hour 列生成值,我能够生成一个具有较少排序、嵌套循环和流聚合操作的计划。由于我不知道原始查询中这些操作的成本,我不知道这是否会产生更好的结果,因为在计划中看到更少的东西并不一定意味着改进。

WITH processed AS (
    SELECT *, dateadd(hour, datediff(hour, 0, Timestamp), 0) as dt_hour
    FROM InterfaceAvailability_CS_Detail_hist
)
SELECT DISTINCT NodeID, dt_hour
,AVG(Availability)  
    OVER (PARTITION BY NodeID, dt_hour) AS avg  
,PERCENTILE_CONT(0.9) WITHIN GROUP (ORDER BY Availability)  
    OVER (PARTITION BY NodeID, dt_hour) AS perc90  
,MAX(Availability)  
    OVER (PARTITION BY NodeID, dt_hour) AS max  
FROM processed
order by NodeID, dt_hour;

【讨论】:

谢谢,丹尼尔!

以上是关于SQL Server:使用具有相同 OVER 子句的多个聚合/分析函数?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用具有相同值的 OVER 子句的 SUM 函数按列返回正确的总和?

基于 OVER PARTITION BY 子句的 SQL 计算列

在 OVER 子句中使用 ORDER BY

SQL Server之排序函数

SQL Server之排序函数

使用 SQL Server 复制 Oracle 的 RANGE BETWEEN 窗口子句语法