2

我有一个名为 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))

行数 = 6

SELECT DBO.DATEONLY(INCOMING) AS DATA, COUNT(*) AS SOULS
FROM HELL
GROUP BY DBO.DATEONLY(INCOMING)

行数 = 32

在我的真实场景中,这 32 行变成了数百万行计数。如果他们是同一件事,发生了什么?!我如何优化它以防止更改我的整个应用程序?

非常感谢!

4

3 回答 3

3

标量值的用户定义函数执行在 sql server 中效率不是很高——它本质上为每个调用执行单独的执行调用,即表中的每一行。Adam Machanic 在这个主题上有一篇很好的文章,它描述了标量 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
于 2011-07-12T19:36:29.843 回答
1

这是因为每次都会对每一行评估 UDF。您所遇到的情况记录在博客文章中:http: //blogs.msdn.com/b/sqlserverfaq/archive/2009/10/06/performance-benefits-of-using-expression-over-user-defined-functions .aspx

于 2011-07-12T19:45:22.860 回答
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))

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

于 2011-07-14T11:34:33.513 回答