在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秒内运行,并以并行方式运行。
有人可以试着解释为什么会这样吗?
答案 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。