我有一个在where子句中指定值时运行速度快(< 1s)的视图:
SELECT *
FROM vwPayments
WHERE AccountId = 8155
...但是当该值是变量时运行缓慢(~3s):
DECLARE @AccountId BIGINT = 8155
SELECT *
FROM vwPayments
WHERE AccountId = @AccountId
为什么第二个查询的执行计划不同?为什么它运行得这么慢?
答案 0 :(得分:4)
在第一种情况下,编译语句时参数值是已知的。优化程序使用统计直方图为该特定参数值生成最佳计划。
定义局部变量时,SQL Server无法使用参数值来查找“最佳值”。由于参数值在编译时未知,因此优化程序根据“均匀分布”计算估计的行数。优化器提出了一个对任何可能的输入参数值都“足够好”的计划。
可以找到另一篇几乎完全描述您案例的有趣文章here。
答案 1 :(得分:2)
简而言之,当值是已知值时,查询优化器用于选择最佳计划的统计分析选择搜索,并且当值未知时,它可以利用统计数据和扫描。它在第二个选择中选择扫描,因为计划是在where子句的值已知之前编译的。
虽然我很少建议在这种特定情况下使用查询分析器,但您可以使用forceseek提示或其他查询提示来覆盖引擎。但请注意,找到一种方法来获得引擎帮助的最佳计划是一个更好的解决方案。
我做了一个快速的Google,发现decent article更深入地影响了查询计划的局部变量概念。
答案 2 :(得分:1)
DECLARE @Local_AccountId BIGINT = @AccountId
SELECT *
FROM vwPayments
WHERE AccountId = @Local_AccountId
OPTION(RECOMPILE)
它对我有用
答案 3 :(得分:0)
它可能是参数嗅探。尝试并执行以下操作 - 我假设它在存储过程中?
DECLARE @Local_AccountId BIGINT = @AccountId SELECT * FROM vwPayments WHERE AccountId = @Local_AccountId
有关参数嗅探的详细信息,您可以查看以下链接:http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx
查看结果是否不同。我多次遇到过这个问题,特别是如果在峰值期间调用了很多查询,而缓存的执行计划是在非高峰时创建的。
另一种选择,但在您的情况下,您不应该将“WITH RECOMPILE”添加到过程定义中。这将导致每次调用过程时重新编译该过程。查看http://www.techrepublic.com/article/understanding-sql-servers-with-recompile-option/5662581
答案 4 :(得分:0)
我认为@souplex提出了一个非常好的观点
基本上在第一种情况下,它只是一个数字,易于系统理解,而第二种情况是变量,这意味着每次系统需要找到它的值,并检查每个语句,这是一个不同的方法