2016-08-03 80 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