2016-08-03 77 views
1

我正在优化一些查询并遇到了一个奇怪的问题,我不知道该如何解释。使用SQL Server 2012与下面的代码:TSQL:静态变量与where子句中的计算

DECLARE @startdate DATETIME2 = DATEADD(day,-1,GETDATE()), 
     @enddate DATETIME2 = GETDATE() 

SELECT * 
FROM table1 WITH(NOLOCK) 
WHERE somedate BETWEEN DATEADD(day,-1,GETDATE()) AND GETDATE() 
    AND somestate = 'NV' 

SELECT * 
FROM table1 WITH(NOLOCK) 
WHERE somedate BETWEEN @startdate AND @enddate 
    AND somestate = 'NV' 

望着实际执行计划,第一选择有一个索引查找和键查找,其中,第二有一个聚集索引扫描。由于SELECT与功能性用途基本相同,因此我不确定为什么执行计划中存在差异。我最后一位DBA告诉我说,在WHERE条款中声明带有值的变量要比使用WHERE条款中的计算要好,但这似乎与该声明相反。我希望澄清是什么原因造成这两个陈述之间的巨大差距。我确实试图寻找一些关于这方面的答案,但没有太多的运气,如果有人能指出我正确的方向,我会非常感激。

谢谢!

+0

设置[坏习惯踢 - 把NOLOCK无处不在](http://blogs.sqlsentry.com/aaronbertrand/bad-habits-nolock-everywhere/) - 它是*不推荐*到处使用 - 相当相反! –

+0

我猜在第二种情况下,sql服务器不知道startdate和enddate是相关的,他期望任何值,所以他选择扫描(相隔日期)。 –

回答

0

我认为你在where子句中使用计算被认为是有害的时候会有些误解。使用包含将用于建立索引的列的计算是当您遇到性能问题时,因为它无法有效地在计算上执行索引查找。在你的例子中,索引列(somedate)不在计算中,所以它不应该对你的索引产生负面影响。请参阅Sql Server Query Performance以获取关于SARG的进一步说明(您在WHERE子句中使用计算引用的问题)。

如果您正在查看SSMS中的执行计划,我会建议检查它是否建议任何索引,因为第二个计划执行集群扫描而不是查找会让我认为您可能需要创建更优化的索引为您的查询。

最后,如果您看到通常表示您的查询未优化的密钥查询(Key Lookup Showplan Operator)。

在非性能笔记上,Microsoft还建议使用> = < =而不是日期之间以避免意外重叠,但我认为这不适用于您的情况。

+0

谢谢安东尼的信息。这些选择的初始版本没有作为子句的一部分,并且具有与此非常相似的结果,因为变量版本进行了聚集索引扫描,并且计算的那个没有并且没有任何建议执行计划中的索引要么更​​令我困惑,因为我不知道如何引入变量会强制索引扫描。有趣的是,包含somestate的新版本在变量版本上缺少索引,但在计算版本上没有索引。 – Xiphoen