索引查找用于查询但索引扫描存储过程中

时间:2014-10-13 12:25:19

标签: sql-server tsql sql-server-2008-r2 sql-execution-plan

我在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会产生影响?如果您需要我提供更多信息,请告诉我。

提前致谢,

汤姆。

3 个答案:

答案 0 :(得分:2)

使用RECOMPILE OPTION创建SP,然后检查执行计划。 关于以下内容的精彩文章:

http://www.mssqltips.com/sqlservertip/3257/different-approaches-to-correct-sql-server-parameter-sniffing/

答案 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类型,那么可能会发生一些隐式会话,这会导致索引扫描。