T-SQL 中多个字段中的相同 window 函数:优化?
Same window function in multiple fields in T-SQL: optimization?
我在 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]
它是被评估了两次还是查询优化器第二次重用了结果?
提前致谢
我们可以像下面这样重写查询,以便只使用一次该函数吗?
-- 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];
您可以通过查看 实际 执行计划(例如 运行 使用 "include actual execution plan" 开启)。
如果您有一个支持 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;
我在 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]
它是被评估了两次还是查询优化器第二次重用了结果? 提前致谢
我们可以像下面这样重写查询,以便只使用一次该函数吗?
-- 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];
您可以通过查看 实际 执行计划(例如 运行 使用 "include actual execution plan" 开启)。
如果您有一个支持 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;