T-SQL 中多个字段中的相同窗口函数:优化?

Posted

技术标签:

【中文标题】T-SQL 中多个字段中的相同窗口函数:优化?【英文标题】:Same window function in multiple fields in T-SQL: optimization? 【发布时间】:2017-10-11 12:04:32 【问题描述】:

我在 T-SQL SELECT 的多个 WHEN 中使用了相同的窗口函数。

SELECT 
    ModuleUsage = CASE
        WHEN Operation = 1 and OperationResult=1 and 1 != LAG(operation) OVER(
            PARTITION BY moduleid, clientname
            ORDER BY moduleid, clientname, timestamp, operation
        )
            THEN 1
        WHEN Operation = 2 and OperationResult=3 and 1 = LAG(operation) OVER(
            PARTITION BY moduleid, clientname
            ORDER BY moduleid, clientname, timestamp, operation
        )
            THEN -1
        ELSE 0
    END
    , *
FROM [dbo].[LicencesTracing]

是计算两次还是查询优化器第二次重用结果? 提前致谢

【问题讨论】:

你可以自己测试一下。使用 `SET STATISTICS` 并通过一个窗口调用进行查询。然后通过两个电话进行完整的查询。你觉得有什么不同吗? 【参考方案1】:

我们可以像下面这样重写查询,以便只使用一次函数吗?

       -- window function <> 1
SELECT CASE WHEN LAG(operation) OVER(PARTITION BY moduleid, clientname ORDER BY moduleid, clientname, timestamp, operation) <> 1

            THEN CASE WHEN Operation = 1 and OperationResult=1 THEN 1 ELSE 0 END

       -- window function = 1
       ELSE

            CASE WHEN Operation = 2 and OperationResult=3 THEN -1 ELSE 0 END
       END AS ModuleUsage
      ,*
FROM [dbo].[LicencesTracing];

而我使用IIF 会简化代码:

SELECT CASE WHEN LAG(operation) OVER(PARTITION BY moduleid, clientname ORDER BY moduleid, clientname, timestamp, operation) <> 1 
            THEN IIF(Operation = 1 and OperationResult=1, 1, 0)
            ELSE IIF(Operation = 2 and OperationResult=3, -1, 0)
       END AS ModuleUsage
      ,*
FROM [dbo].[LicencesTracing]; 

【讨论】:

如果 IIF 使用 2012+ ,则 IIF 将只是代码 ;) ...否则他们只会得到一个错误 @AlanBurstein 他们正在使用 2012+,因为他们正在使用 LAG 函数 ;) 是的。呃。在进一步评论之前,我需要喝完咖啡。 ;)【参考方案2】:

您可以通过查看 实际 执行计划来确定您的 Window 函数是否被评估一次或多次(例如,在“包含实际执行计划”打开的情况下运行查询)。

如果您有一个索引来支持该窗口功能,那么它真的没关系,因为操作很便宜。 POC index 对此查询非常有帮助。索引如下所示:

CREATE nonclustered index xxx on dbo.LicencesTracing(moduleid, clientname, timestamp, operation)
INCLUDE <whatever columns you are returning>;

您可以简化查询强制优化器通过在子查询中计算 Window 函数来评估它;像这样的东西: (请注意,我无法对此进行测试...)

SELECT ModuleUsage = CASE 
    WHEN Operation = 1 and OperationResult = 1 and lagOp <> 1 THEN  1
    WHEN Operation = 2 and OperationResult = 3 and lagOp =  1 THEN -1 ELSE 0 
END
FROM
(
  SELECT Operation, OperationResult, lagOp =
    LAG(operation) OVER(PARTITION BY moduleid, clientname 
                   ORDER BY moduleid, clientname, timestamp, operation), *
  FROM [dbo].[LicencesTracing]
) sub;

【讨论】:

谢谢你,Alan:你实际上给了我关于优化的非常有用的见解。我将@gotqn 的答案标记为答案,因为他从根本上解决了这个问题。

以上是关于T-SQL 中多个字段中的相同窗口函数:优化?的主要内容,如果未能解决你的问题,请参考以下文章

sparksql比hivesql优化的点(窗口函数)

Microsoft SQL Server 2022 新特性之 T-SQL 语言增强

Microsoft SQL Server 2022 新特性之 T-SQL 语言增强

T-SQL 窗口函数

窗口聚合函数与分组聚合函数的异同

PANDAS 中类似 SQL 的窗口函数:Python Pandas Dataframe 中的行编号