使用函数的SQL Server查询非常慢

时间:2012-12-03 05:38:57

标签: sql sql-server performance tsql sql-function

这是从前一个问题开始的:

SQL Server Query time out depending on Where Clause

根据where子句,查询的运行速度会非常慢。我重写了该查询使用CTE并很好地避免了问题,但从未找到答案。

另一个类似的查询最近被调整为添加另一个字段,突然它的性能从大约需要30秒才能运行并返回10,000行,超过10个小时(并最终返回相同的结果集)。今天我开始对这个进行故障排除,发现了一些奇怪的东西。

我经常需要从datetime值中提取日期部分,因此我将逻辑写入函数:

CREATE FUNCTION [dbo].[cDate] ( @pInputDate    DATETIME )
RETURNS DATETIME
BEGIN
        RETURN CAST(CONVERT(VARCHAR(10), @pInputDate, 111) AS DATETIME)
END
GO

我在这个新的低效查询中发现,如果我用查询中的CAST(CONVERT(VARCHAR(10), @pInputDate, 111) AS DATETIME)内联替换了该函数,则查询执行的速度从~10小时降至不到2秒。我看到估计的执行计划没有区别。顺便说一句,这不是添加的领域。我假设添加另一个字段以某种方式导致执行计划改变并放大了上述条件。

我的问题是,这是正常的吗?如上所述,我使用重复过程的函数,因为如果你找到一种更有效的方法,它们更容易维护,记忆和更新。我应该为我的职能做些什么来提高他们的表现吗?

2 个答案:

答案 0 :(得分:5)

如果您必须将其封装在一个函数中,请参阅Scalar functions, inlining, and performance: An entertaining title for a boring post

重写如下

CREATE FUNCTION dbo.cDate_Inline
(
    @pInputDate DATETIME
)
RETURNS TABLE
AS
    RETURN
    (
        SELECT DATEADD(day, DATEDIFF(Day, 0, @pInputDate), 0) AS [Date]
    )

然后代替

SELECT *,
       [dbo].[cDate](modify_date) AS modified
FROM   sys.objects 

使用

SELECT *,
       ca.Date AS modified
FROM   sys.objects
       CROSS APPLY dbo.cDate_Inline(modify_date) ca 

这将由查询优化器内联到计划中。

答案 1 :(得分:0)

我会尝试添加另一个变量来进行声明并返回。对此的思考过程可能是您的转换和转换以改变输入的日期时间可能是瓶颈。这可能不是这种情况,但通常如果您在范围中设置一个新变量,请进行调节并将其绑定到该变量并返回该变量,这可能有助于提高速度。我倾向于尽可能远离标量函数,但是当你开始使用更大的数据集时,它们会有很多性能问题。只是一个建议它可能会或可能没有帮助,但它会将返回隔离到一个独立于输入的新对象:

CREATE FUNCTION [dbo].[cDate] ( @pInputDate    DATETIME )
RETURNS DATETIME
BEGIN
Declare @Output datetime  = CAST(CONVERT(VARCHAR(10), @pInputDate, 111) AS DATETIME)  -- 2008 method and newer

Declare @Output datetime;

Select @Output  = CAST(CONVERT(VARCHAR(10), @pInputDate, 111) AS DATETIME)  -- 2005 and prior method 


return @Output
END
GO