由于内部使用的功能,存储过程执行时间很长

时间:2016-04-07 10:05:33

标签: sql sql-server stored-procedures sql-server-2012 user-defined-functions

在SQL Server 2012中,我有以下用户定义的函数:

CREATE FUNCTION [dbo].[udfMaxDateTime]()
RETURNS datetime
AS 
BEGIN 
    RETURN '99991231';
END;

然后在如下的存储过程中使用它:

DECLARE @MaxDate datetime = dbo.udfMaxDateTime();

DELETE FROM TABLE_NAME
WHERE 
    ValidTo = @MaxDate
AND
    Id NOT IN
    (
        SELECT 
            MAX(Id)
        FROM 
            TABLE_NAME 
        WHERE
            ValidTo = @MaxDate
        GROUP 
        BY 
            COL1
        );

现在,如果我使用上面的代码运行存储过程,则执行大约需要12秒。 (1,200万行)

如果我将WHERE子句更改为 ValidTo =' 99991231' ,那么存储过程将在1秒内运行,并以并行方式运行。

有人可以试着解释为什么会这样吗?

1 个答案:

答案 0 :(得分:3)

这不是因为用户定义的函数,而是因为变量。

@MaxDate查询中使用变量DELETE时,优化程序在生成执行计划时不知道此变量的值。因此,当您在查询中进行相等性比较时,它会根据ValidTo列上的可用统计信息以及基数估算的一些内置启发式规则生成计划。

在查询中使用文字常量时,优化器会知道其值并可以生成更有效的计划。

如果添加OPTION(RECOMPILE),则执行计划将不会被缓存,并且将始终重新生成,并且优化程序将知道所有参数值。查询很可能会使用此选项快速运行。此选项确实会增加一定的开销,但只有在经常运行查询时才会显着。

DECLARE @MaxDate datetime = dbo.udfMaxDateTime();

DELETE FROM TABLE_NAME
WHERE 
    ValidTo = @MaxDate
AND
    Id NOT IN
    (
        SELECT 
            MAX(Id)
        FROM 
            TABLE_NAME 
        WHERE
            ValidTo = @MaxDate
        GROUP BY 
            COL1
    )
OPTION(RECOMPILE);

我强烈建议阅读Erland Sommarskog的Slow in the Application, Fast in SSMS