这个问题并非关于如何找到解决方案,而是要解释我从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秒内执行。这里的团队非常棒。
现在,女士们,先生们,有谁可以解释这种行为?
答案 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将不会考虑参数来影响执行计划,因此您可以从查询中获得更快的响应。