2012-08-09 59 views
1

我有一個非常大的表(1500萬行,這是一個審計表)。硬編碼日期字符串比SELECT中的DateTime快得多?

我需要運行檢查出現在審計表是在特定日期之後查詢並符合一定的標準(我要尋找的是發生在只有當天的審計記錄)

當我運行:

SELECT Field1, Field2 FROM AUDIT_TABLE WHERE AUDIT_DATE >= '8/9/12' 

結果回來相當快(數秒,不壞的15M行)

當我運行:

SELECT Field1, Field2 FROM AUDIT_TABLE WHERE AUDIT_DATE >= @DateTime 

它需要11-15秒,並進行全表掃描。

我查詢的實際字段是DATETIME類型,索引也在該字段中。

+0

AUDIT_TABLE是在AUDIT_DATE索引還是分區?您的第二個示例可能會阻止索引被使用。 – stevepastelan 2012-08-09 14:43:20

+0

比較執行計劃;你的參數化版本最有可能有一個最適合所有可能輸入的執行計劃,但可能不是針對特定參數值的最佳計劃... – Mr47 2012-08-09 14:44:24

回答

7

聽起來就像你被一個糟糕的計劃困住了一樣,可能是因爲有人在某個點選擇了足夠多的表,而表掃描是該參數值的最有效方式。試運行查詢這樣一次:

SELECT ... FROM AUDIT_TABLE WHERE AUDIT_DATE >= @DateTIme OPTION (RECOMPILE); 

,然後改變你的代碼是這樣的:

SELECT ... FROM dbo.AUDIT_TABLE WHERE AUDIT_DATE >= @DateTime; 

使用dbo.前綴將至少是防止不同的用戶有不同的模式,防止污染計劃緩存與計劃的不同版本。它也會將未來的查詢與存儲的壞計劃分離。

如果你要選擇最近的行(小%)和很多行之間的差異,我可能會離開OPTION(RECOMPILE)在那裏。每次在重新編譯時支付較小的CPU損失將比爲大多數查詢制定糟糕的計劃要便宜。

另一個竅門我見過用來旁路參數嗅探:

ALTER PROCEDURE dbo.whatever 
    @DateTime DATETIME 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @dt DATETIME; 
    SET @dt = @DateTime; 

    SELECT ... WHERE AUDIT_DATE >= @dt; 
END 
GO 

這是一種骯髒的和直觀的伎倆,但它給了優化的參數值有更好的理解,並有更好的機會來優化爲那個價值。

+0

這非常好,謝謝。我已經使用了dbo前綴(在代碼示例中只留下了少量字符),但對任何讀者來說,這都是很好的建議。正如你所說,似乎必須有一個糟糕的執行計劃。添加選項(RECOMPILE)做了訣竅,它現在在1秒內運行。我曾經在程序層次上嘗試過使用相同的思路,但似乎沒有效果,因爲WHERE子句級別重新編譯。再次感謝! – enforge 2012-08-09 14:56:24