6

I have a view that runs fast (< 1s) when specifying a value in the where clause:

SELECT *
FROM vwPayments
WHERE AccountId = 8155

Execution plan for first query

...but runs slow (~3s) when that value is a variable:

DECLARE @AccountId BIGINT = 8155

SELECT *
FROM vwPayments
WHERE AccountId = @AccountId

Execution plan for second query

Why is the execution plan different for the second query? Why is it running so much slower?

4

5 回答 5

4

In the first case the parameter value was known while compiling the statement. The optimizer used the statistics histogram to generate the best plan for that particular parameter value.

When you defined the local variable, SQL server was not able to use the parameter value to find 'the optimal value'. Since the parameter value is unknown at compile time, the optimizer calculates an estimated number of rows based on 'uniform distribution'. The optimizer came up with a plan that would be 'good enough' for any possible input parameter value.

Another interesting article that almost exactly describes your case can be found here.

于 2013-06-11T03:00:04.020 回答
2

In short the statistical analysis the query optimizer uses to pick the best plan picks a seek when the value is a known value and it can leverage statistics and a scan when the value is not known. It picks a scan in the second choice because the plan is compiled before the value of the where clause is known.

While I rarely recommend bossing the query analyzer around in this specific case you can use a forceseek hint or other query hints to override the engine. Be aware however, that finding a way to get an optimal plan with the engine's help is a MUCH better solution.

I did a quick Google and found a decent article that goes into the concept of local variables affecting query plans more deeply.

于 2013-06-10T22:13:49.920 回答
1
DECLARE @Local_AccountId BIGINT = @AccountId 

SELECT *
FROM vwPayments
WHERE AccountId = @Local_AccountId 
OPTION(RECOMPILE)

It works for me

于 2017-05-09T09:57:27.527 回答
0

It could be parameter sniffing. Try and do the following - I assume it is in a stored procedure?

 
DECLARE @Local_AccountId BIGINT = @AccountId 

SELECT *
FROM vwPayments
WHERE AccountId = @Local_AccountId 

For details about parameter sniffing, you can view this link : http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

See if the results are different. I have encountered this problem several times, especially if the query is being called a lot during peaks and the execution plan cached is one which was created when off-peak.

Another option, but you should not need in your case is adding "WITH RECOMPILE" to a procedure definition. This would cause the procedure to be recompiled every time it is called. View http://www.techrepublic.com/article/understanding-sql-servers-with-recompile-option/5662581

于 2013-06-10T22:13:26.203 回答
0

I think @souplex made a very good point

Basically at the first case it's just a number and easy for system to understand, while the 2nd one is variable which means every time the system need to find the very value of it and do the check for each statement, which is a different method

于 2013-06-11T14:00:22.583 回答