SQL Server使用标量值函数向我显示不同的RowCounts

时间:2011-07-12 18:36:59

标签: sql-server sql-server-2005 sql-date-functions

我有一个名为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行变成了数百万行。如果它们是相同的东西,发生了什么?!如何优化它以防止更改我的整个应用程序?

非常感谢!

3 个答案:

答案 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))

您可以在传入列上创建索引以避免性能降级。