存储过程性能 - 这是WILD?

时间:2011-12-05 11:25:26

标签: c# sql-server-2008 stored-procedures

这个问题并非关于如何找到解决方案,而是要解释我从SQL Server中看到的奇怪的行为。

我有一个带有以下签名的存储过程:

alter procedure MySP @param1 uniqueidentifier, 
                     @param2 uniqueidentifier, 
                     @param3 uniqueidentifier

给定一组参数,这个过程需要很长时间才能从C#运行(使用SqlCommand.ExecuteReader()) - 大约2分钟。在直接查询会话中使用相同的参数,SP在2秒内运行。

花了很长时间,我甚至不会试图解释我们如何偶然发现这个解决方案,但这就是我们所做的:

在SP的开头,我们声明了3个局部变量并将它们分配给参数的值,如下所示:

declare @param1_copy uniqueidentifier, 
        @param2_copy uniqueidentifier, 
        @param3_copy uniqueidentifier

select @param1_copy = @param1,
       @param2_copy = @param2,
       @param3_copy = @param3

然后,在SP的其余部分,我们用本地副本替换了对输入参数的所有引用。

瞧。 SP在2秒内执行。这里的团队非常棒。

现在,女士们,先生们,有谁可以解释这种行为?

3 个答案:

答案 0 :(得分:8)

这听起来像parameter sniffing

来自微软的定义:

  

“参数嗅探”是指SQL Server的执行环境在编译或重新编译期间“嗅探”当前参数值的过程,并将其传递给查询优化器,以便它们可用于生成可能更快的查询执行计划。 “current”一词是指语句调用中出现的引起编译或重新编译的参数值。

看起来你已经找到了一个修复,另一个是使用EXEC ... WITH RECOMPILE:

  

执行具有非典型参数值的存储过程时,可以使用“EXEC ... WITH RECOMPILE”来确保新查询计划不会替换使用典型参数值编译的现有缓存计划。

答案 1 :(得分:3)

我建议阅读Erland Sommarskog的优秀文章:Slow in the Application, Fast in SSMS? Understanding Performance Mysteries

它有关于这个问题的完整细节。

通常,在缓存查询计划时,会在缓存键中使用某些查询设置。这些设置在默认SSMS设置中与在默认连接字符串上的设置不同,因此可能存在不同的查询计划。

答案 2 :(得分:0)

当我有一个xml类型的参数并且需要花费大量时间来执行时,我遇到了类似的情况。我做了相同的方法并创建了一个局部变量并传递了参数值,并且它运行得非常快:)

当SQL开始编译SP以创建其执行计划时,它会考虑在其参数中传递的值以影响执行计划。但是,如果将参数值分配给局部变量并在整个SP代码中使用该变量,那么SQL将不会考虑参数来影响执行计划,因此您可以从查询中获得更快的响应。