我有一个名为DATEONLY的标量值函数返回DATEADD(DD,0,DATEDIFF(DD,0,@ DATETIME)),就像这样:
CREATE FUNCTION [DBO].[DATEONLY] ( @DATETIME DATETIME )
RETURNS DATETIME
BEGIN
RETURN DATEADD(DD, 0, DATEDIFF(DD, 0, @DATETIME))
END
当我使用我的函数选择一个表时,SQL Server Profiler会计算一个高RowCounts数,而不是直接使用DATEADD(DD,0,DATEDIFF(DD,0,@ DATETIME))。
在我的Dropxbox的公共文件夹中,你可以找到一个可以重现我所说的内容的script.sql,你也可以从我的SQL Server Profiler中找到一个Trace.trc。
script.sql:https://www.dropbox.com/s/gwbh54jqas7fhhc/script.sql
trace.trc:https://www.dropbox.com/s/gwbh54jqas7fhhc/Trace.trc
为了简化,请查看下面的RowCounts。
SELECT DATEADD(DD,0, DATEDIFF(DD,0, INCOMING)) AS DATA, COUNT(*) AS SOULS
FROM HELL
GROUP BY DATEADD(DD,0, DATEDIFF(DD,0, INCOMING))
RowCounts = 6
SELECT DBO.DATEONLY(INCOMING) AS DATA, COUNT(*) AS SOULS
FROM HELL
GROUP BY DBO.DATEONLY(INCOMING)
RowCounts = 32
在我的实际场景中,这32行变成了数百万行。如果它们是相同的东西,发生了什么?!如何优化它以防止更改我的整个应用程序?
非常感谢!
答案 0 :(得分:3)
标量值的用户定义函数执行在sql server中效率不高 - 它实质上是为每个调用执行单独的执行调用,这是表中的每一行。 Adam Machanic在这个主题上有一个很好的post,它描述了标量udf执行以及内联表值函数执行如何更快。
可以重写您的查询以利用tvf中的逻辑,优化程序使用与原始扩展查询相同的查询计划执行,并在执行期间显示相同的RowCounts = 5。
CREATE FUNCTION [DBO].[DATEONLY2] ( @DATETIME DATETIME ) RETURNS TABLE
AS RETURN SELECT DATEADD(DD, 0, DATEDIFF(DD, 0, @DATETIME)) data
select data, count(*) as souls
from
(SELECT (select data from dbo.dateonly2(incoming)) data
FROM HELL) t
GROUP BY data
答案 1 :(得分:1)
这是因为每次对每行评估UDF。您正在体验的内容记录在博客文章中:http://blogs.msdn.com/b/sqlserverfaq/archive/2009/10/06/performance-benefits-of-using-expression-over-user-defined-functions.aspx
答案 2 :(得分:0)
我建议使用以下查询
SELECT DATEADD(DD,0, DATEDIFF(DD,0, INCOMING)) AS DATA, COUNT(*) AS SOULS
FROM HELL
GROUP BY DATEADD(DD,0, DATEDIFF(DD,0, INCOMING))
您可以在传入列上创建索引以避免性能降级。