2010-03-30 95 views
4

我試圖優化一些可怕的複雜的SQL查詢,因爲它需要很長時間才能完成。SQL DATEDIFF(年,...,...)昂貴的計算?

在我的查詢中,我用很多相同的函數動態地創建了SQL語句,所以我創建了一個臨時表,其中每個函數只被調用一次而不是很多次 - 這將我的執行時間減少了3/4 。

所以我的問題是,我可以期待看到很大的差異,如果說,1,000個datediff計算縮小到100?

編輯: 查詢看起來像這樣:

SELECT DISTINCT M.MID, M.RE FROM #TEMP INNER JOIN M ON #TEMP.MID=M.MID 
WHERE (#TEMP.Property1=1) AND 
DATEDIFF(year, M.DOB, @date2) >= 15 AND DATEDIFF(year, M.DOB, @date2) <= 17 

其中這些被動態生成的作爲字符串(一起放在星星點點),然後執行,使得各種參數可以沿着每個迭代被改變 - 主要是最後一行,包含各種DATEDIFF查詢。

這裏約有420個查詢,其中這些datediffs的計算方式如此。我知道我可以很容易地將它們全部放入臨時表中(1,000年以上),但它是否值得,它會在幾秒鐘內發生什麼變化?我希望比十分之幾秒有更好的改善。

+3

發佈查詢 - 確實無法幫助您確認在2深度子查詢中執行DATEDIFF時的假設... – 2010-03-30 17:46:49

回答

13

這完全取決於您所做的事情,以誠實的方式表現。

例如,如果您在WHERE子句中使用DATEDIFF(或實際上任何其他函數),那麼這將成爲性能較差的原因,因爲它會阻止在該列上使用索引。

例如基本示例,查找2009年的所有記錄

WHERE DATEDIFF(yyyy, DateColumn, '2009-01-01') = 0 

不能很好地使用DateColumn上的索引。而一個更好的解決方案,提供最佳的指數用法是:

WHERE DateColumn >= '2009-01-01' AND DateColumn < '2010-01-01' 

recently blogged有關這使得(與性能統計/執行計劃比較),如果你有興趣的差異。

這比將DATEDIFF作爲結果集中的列返回的代價要昂貴。

我會從識別花費時間最多的單個查詢開始。檢查執行計劃,看看問題出在哪裏,然後從那裏調整。

編輯: 根據您給出的示例查詢,您可以嘗試在WHERE子句中刪除DATEDIFF的使用。在給定日期找到每個10歲的人的基本示例 - 我認爲數學是正確的,但無論如何你都明白了!給它一個快速測試,並且看起來很好。應該很容易適應你的情況。如果您想查找某個日期的(例如)15歲和17歲之間的人,那麼使用此方法也可以。

-- Assuming @Date2 is set to the date at which you want to calculate someone's age 
DECLARE @AgeAtDate INTEGER 
SET @AgeAtDate = 10 

DECLARE @BornFrom DATETIME 
DECLARE @BornUntil DATETIME 
SELECT @BornFrom = DATEADD(yyyy, -(@AgeAtDate + 1), @Date2) 
SELECT @BornUntil = DATEADD(yyyy, [email protected] , @Date2) 

SELECT DOB 
FROM YourTable 
WHERE DOB > @BornFrom AND DOB <= @BornUntil 

需要補充的一個重要注意事項是來自DOB的年齡計算,這種方法更準確。您目前的實施只考慮出生年份,而不是實際的一天(例如,2009年12月1日出生的人將在2010年1月1日出現1歲,直到2010年12月1日不是1歲)。

希望這會有所幫助。

+2

正確,當然這適用於幾乎* any *函數用於包裝索引列,不只是'DATEDIFF'。 – Aaronaught 2010-03-30 18:02:08

+0

@Aarounaught - 是的,謝謝你的收穫。我已經更新了我的答案,以便更明確 – AdaTheDev 2010-03-30 18:05:02

+0

是的,很好的答案 – HLGEM 2010-03-30 19:17:38

0

與其他處理日期時間值的方法(如字符串)相比,DATEDIFF相當高效。 (see this SO answer)。

在這種情況下,您聽起來像是在翻閱相同的數據,這可能比使用臨時表更昂貴。例如,將生成統計信息。

0

您可能可以做的一件事是提高性能,可能是在MID的臨時表上放置一個索引。

檢查您的執行計劃,看看它是否有幫助(可能取決於臨時表中的行數)。