我在SQL Server 2008 R2中遇到了一些奇怪的行为。
我有以下查询:
UPDATE TableToUpdate
SET ColumnToUpdate = @ColumnValue
WHERE ColumnA IN
(
SELECT ColumnA
FROM SubQ1Table
WHERE ColumnToUpdateReference = @ColumnValue
)
and ColumnB in
(
SELECT ColumnB
FROM SubQ2Table
WHERE ColumnToUpdateReference = @ColumnValue
)
当我手动运行查询并按如下方式声明变量@ColumnValue时:
DECLARE @ColumnValue INT = 123;
它在几秒钟内运行并在索引上进行索引搜索,该索引覆盖TableToUpdate表上的列ColumnA,ColumnB和ColumnToUpdate。
当我使用精确查询创建存储过程时,除了传入参数之外...例如:
EXEC sp_Query 123
索引扫描在同一索引上使用,大约需要30秒才能完成。
我查看了两个不同的查询计划。从左到右阅读第一个区别是存储过程似乎做了嵌套循环(Inner Join)而直接查询执行了Stream Aggregate(Aggregate)。
为什么通过存储过程调用此SQL会产生影响?如果您需要我提供更多信息,请告诉我。
提前致谢,
汤姆。
答案 0 :(得分:2)
使用RECOMPILE OPTION创建SP,然后检查执行计划。 关于以下内容的精彩文章:
答案 1 :(得分:2)
就像GarethD建议的那样,听起来它可能是参数嗅探,如果你不知道那是什么,让我(尝试)解释。
SQL Server通过" sniffing"来编译存储过程。第一次执行过程时发送的参数,并将此执行的计划放入计划高速缓存中以供将来参考。
每次执行该过程时,SQL Server都会从缓存中检索执行计划并使用它(除非有重新编译的原因)。
如果第一次执行存储过程时会出现问题,则会使用一组参数为该组参数生成可接受的计划,但对其他更常见的参数集非常不利。
我可以想到有几种解决方法:
有一些解决方法可以解决这个问题。
OPTION (RECOMPILE)
OPTION (OPTIMIZE FOR (@VARIABLE=VALUE))
OPTION (OPTIMIZE FOR (@VARIABLE UNKNOWN))
Use local variables
这取决于您最适合自己的设置,但请仔细阅读。
SQL Server - parameter sniffing
Parameter Sniffing (or Spoofing) in SQL Server
https://www.simple-talk.com/sql/t-sql-programming/parameter-sniffing/
另外,请注意使用' sp _'在命名存储过程时 - 它是一个很大的不。 查看this article,详细介绍了使用sp _。
的全面检查答案 2 :(得分:2)
您可以检查存储过程中的数据类型参数吗?
如果它不是int类型,那么可能会发生一些隐式会话,这会导致索引扫描。