2010-06-23 129 views
0

我想用存儲過程編寫一個查詢並使用多個過濾器,但我想避免動態SQL。Sql Server查詢優化

說我的參數可以爲空(@ filter1,@ filter2,@ filter3 ...)。我可能會解決這個問題的一種方法是:

SELECT col1, col2, col3 
FROM table 
WHERE col1 = ISNULL(@filter1, col1) 
AND col2 = ISNULL(@filter2, col2) 
AND col3 = ISNULL(@filter3, col3) 

如果不是null,則會通過適當的過濾器進行過濾。問題是: 1)這是一種很好的做法嗎? 2)優化器會優化col1 = col1 out還是會影響查詢性能?

+3

性能會很糟糕,因爲有很多可能的組合,查詢計劃不可能被緩存。動態SQL是一個更好的選擇。 – 2010-06-23 20:09:49

回答

3

Erland Sommarskog將這種類型的問題放在一起an excellent article。我強烈建議通讀它。

0

ISNULL可能會傷害索引使用,所以我不會說這是理想的,但如果您需要上述功能,我不確定是否有解決方法。

你可以看看你的執行計劃,看看你期望使用的索引是否被使用?

+0

這個構造通常工作正常。 COALESCE可以成爲殺手,因爲它如何對待數據類型 – gbn 2010-06-23 20:14:55

+0

有趣的是,ISNULL vs COALESCE的任何推薦讀物? – 2010-06-23 20:21:06

0

1)這是一種很好的做法嗎? 2)優化器會優化col1 = col1 out還是會影響查詢性能?

是的,這是一個很好的做法。

有些RDBMS會優化它,有些不會。如果您將其稱爲準備好的聲明,則不會。

不要過早地優化;對於大多數情況來說,成本差異可以忽略不計,或者如果不是,可以忽略適當的指數。

專注於編寫明確表達你正在做的事情的代碼。在我看來,這個成語很清晰簡潔。

+1

我很大的支持者並沒有試圖過早地進行優化,但是在這種情況下,性能影響往往很大,而且索引不太可能提供幫助,因爲查詢可能每次都會做出不同的事情。這種類型的功能通常是系統範圍的(即你需要在許多不同的表上進行動態搜索),因此在編寫50個SP之前必須知道你的一般方法,然後你必須重寫。 – 2010-06-23 20:17:59

+1

這並不是過早的優化,它應該在每個數據庫上進行性能優化。當技術之間的表現存在差異時,應從一開始就選擇表現最好的一種。 Databasea是非常難以重構的。表現已成問題爲時已晚。過早優化並不意味着沒有優化。 – HLGEM 2010-06-23 20:35:55

0

如果您希望這個表將增長到任何實質性的規模,這是不是一個好主意,因爲查詢優化器將不緩存執行計劃和優化,在吸用的情況下處理這樣的,因爲它不能輕易告訴在編譯時執行路徑將是什麼。

只要在客戶端使用where子句中的正確過濾器生成查詢,而不是嘗試寫入單個全部捕獲查詢,那將會好得多。

0

根據我的經驗(運行大表上一些基準)以下:

(col1 = @filter or @filter IS NULL) 

比快得多:

col1 = ISNULL(@filter1, col1) 
1

關於優化的條件:你必須知道的是,一個編制計劃必須滿足任何變量值。因此,當生成計劃時,SQL Server 必須創建一個訪問計劃,該計劃在@ filter1爲NULL時起作用,並且在@ filter1不爲NULL時也起作用。結果幾乎總是一個掃描。

湯姆H.鏈接的文章詳細介紹了這一點。