SQL Server 2005 - 相同的查询,相同的服务器,两个不同的执行计划

时间:2012-08-27 22:33:57

标签: sql indexing

我已经在我们的服务器上持续发布了几周的问题。有一个简单的查询可以在几个不同的存储过程中运行,但在其中一些中,查询可能需要将近4分钟才能运行。一些程序具有完全相同的查询,并且它们在< 1秒。从查询窗口运行它返回< 1秒。

我无法重新创建 - 我无法运行用户正在运行的过程(因为它会更改数据),并且我们的测试服务器上不会出现问题。我有时可以重新编译(F5)程序,它似乎重新创建执行计划,并修复它一段时间,但它总是返回。

查询非常简单:

SELECT '1' 
FROM TRANSACTION_LOG WITH (NOLOCK) 
WHERE TYPE = 15 AND SERIAL_NO = @P_TRAVELER_SERIAL
  • TRANSACTION_LOG有~90m行
  • TYPE具有非聚集索引
  • SERIAL_NO具有非聚集索引

经过一些研究和剖析器捕获后,我在执行计划中发现了一些奇怪的东西。我设法在快速运行时捕获执行计划,在运行缓慢时捕获另一个执行计划。这些来自完全相同的过程,完全相同的查询 - 唯一的区别是@P_TRAVELER_SERIAL参数的值:

FAST:

Compute Scalar(DEFINE:([Expr1005]=CASE WHEN [Expr1006] THEN (1) ELSE (0) END))          
  |--Nested Loops(Left Semi Join, DEFINE:([Expr1006] = [PROBE VALUE]))
    |--Constant Scan
    |--Filter(WHERE:([MICS].[dbo].[Transaction_Log].[TYPE]=(15)))
      |--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000], [Expr1010]) WITH UNORDERED PREFETCH)
        |--Index Seek(OBJECT:([MICS].[dbo].[Transaction_Log].[IX_SERIAL_NO]), SEEK:([MICS].[dbo].[Transaction_Log].[SERIAL_NO]=[@P_TRAVELER_SERIAL]) ORDERED FORWARD)
        |--RID Lookup(OBJECT:([MICS].[dbo].[Transaction_Log]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD)

SLOW:

Compute Scalar(DEFINE:([Expr1005]=CASE WHEN [Expr1006] THEN (1) ELSE (0) END))
  |--Nested Loops(Left Semi Join, DEFINE:([Expr1006] = [PROBE VALUE]))
    |--Constant Scan 
    |--Table Scan(OBJECT:([MICS].[dbo].[Transaction_Log]), WHERE:([MICS].[dbo].[Transaction_Log].[TYPE]=(15) AND [MICS].[dbo].[Transaction_Log].[SERIAL_NO]=[@P_TRAVELER_SERIAL]))

为什么它会使用一个计划的索引搜索和另一个计划的表扫描?这是相同的查询和相同的程序?桌面活动会与它有什么关系吗?这是一张忙碌的桌子......

由于

1 个答案:

答案 0 :(得分:1)

这听起来像是一个参数嗅探问题。随着时间的推移,SQL Server会确定您的过程的执行计划已过期,并且下次执行该过程时,将编译新计划。不幸的是,当发生这种情况时,SQL Server在确定为该过程生成(和缓存)的计划时使用当前传入的值。如果当时传入的值恰好不常见,SQL Server可能会构建并随后缓存执行表扫描的执行计划。虽然这对于传入的不常见值可能是最佳的,但对于从索引搜索中受益的值来说,显然不是那么理想。

有关更多信息和可能的解决方法,请参阅此technet博客文章。 http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx