Reputation: 11
I've been fighting with an ongoing issue on our server for a few weeks now. There is a simple query that gets run in several different stored procedures, but in a few of them, the query can take nearly 4 minutes to run. Some procedures have this exact same query and they run in < 1 second. Running it from a query window returns in < 1 second.
I cannot recreate this - I can't run the procedure the user is running (because it changes data), and the problem does not arise on our test server. I can sometimes recompile (F5) the procedure, which seems to recreate the execution plan, and fix it for a while, but it always returns.
The query is as simple as:
SELECT '1'
FROM TRANSACTION_LOG WITH (NOLOCK)
WHERE TYPE = 15 AND SERIAL_NO = @P_TRAVELER_SERIAL
TRANSACTION_LOG
has ~90m rows TYPE
has a non-clustered indexSERIAL_NO
has a non-clustered indexAfter some research and profiler capturing, I found something odd in the execution plan. I managed to capture the execution plan while it was running quickly and another when it was running slowly. These are from the exact same procedure, exact same query - the only difference would be the value of the @P_TRAVELER_SERIAL
parameter:
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]))
Why would it use an index seek with one plan and a table scan with the other? It's the same query and the same procedure? Would table activity have anything to do with it? It's a busy table...
Thanks
Upvotes: 1
Views: 1243
Reputation: 11
This sounds like a parameter sniffing issue to me. What happens is that over time SQL Server determines that the execution plan for your procedure is out of date, and the next time the procedure is executed a new plan is compiled. Unfortunately when this happens, SQL server uses the currently passed in value(s) when determining what plan to generate (and cache) for the procedure. If the value(s) that were passed in at that time happen to be uncommon enough, SQL Server may build, and subsequently cache, an execution plan that does a table scan. While this may be optimal for the uncommon value that was passed in, it's clearly not so ideal for a value that would benefit from an index seek.
For more info and possible workarounds, see this technet blog post. http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx
Upvotes: 1