2010-11-04 53 views
0

我有以下兩個SQL語句「IF..ElseIf..Else」 或 「Where子句」 引導存儲過程結果

第一招:

IF(@User_Id IS NULL) 
BEGIN 
     SELECT * 
     FROM [UserTable] 
END 
ELSE   
BEGIN     
     SELECT * 
    FROM [UserTable] AS u 
    WHERE u.[Id] = @User_Id     
END 

第二個:

SELECT * 
FROM [UserTable] AS u 
WHERE (@User_Id IS NULL OR u.[Id] = @User_Id) 

這兩個查詢都會被封裝在自己的存儲過程中。我懷疑IF語句在SQL上導致了很多重新編譯。我面臨要麼將IF語句的每個部分分離到它自己的存儲過程,要麼用WHERE子句替換整個IF語句(在第二個SQL語句中說明)

我的問題是:有什麼區別從性能角度來看這兩個語句,以及SQL如何處理每條語句?

謝謝。

+1

如果您使用的是SQL Server 2005+,那麼爲什麼不看執行計劃以查看其差別呢? – 2010-11-04 09:55:38

+0

另外,如果您的ELSE語句中的@User_Id IS NOT NULL不需要重新測試,因爲您知道它不是NULL。 – 2010-11-04 09:56:15

+0

Ardman我同意,「其他如果」可能是一個「其他」:) – MikeStichling 2010-11-04 10:00:19

回答

0

這兩種解決方案都會生成相同數量的彙編。

第一種解決方案查詢優化器可以爲每個不同的查詢提供最佳方案。如果Id列上的索引存在,則第一個查詢(在IF的NULL分支上)沒有太多可以優化的內容,但是第二個查詢(在ID的NOT NULL分支上)可以優化。

但第二種解決方案是優化災難。無論@User_Id參數的值是多少,優化器都必須提出一個適用於參數值的任何值的計劃。因此,無論@User_Id的值,計劃將總是使用次優表掃描。沒有辦法解決這個問題,這是而不是參數嗅探,如有些人可能認爲。只是計劃的正確性,即使計劃生成時間的值不爲NULL,計劃必須工作即使參數 NULL,也不能使用Id上的索引。

始終,永遠,始終使用第一種形式,並使用明確的IF

+0

謝謝,雖然有點困惑,但SQL如何確定是否需要重新編譯存儲過程。其中一個標準是統計數據的變化。 IF聲明中的兩個不同分支將基於參數值返回非常不同的統計信息。這不會導致存儲過程被標記爲重新編譯? – MikeStichling 2010-11-04 21:51:13

+0

統計信息是對象(表)的屬性,而不是查詢的屬性。因此,這兩個查詢將返回不同的*結果*,但該計劃將根據相同的統計數據(UserTable的統計數據)進行編譯。如果你的查詢是真實的,就像你的帖子一樣,那麼你不必擔心重新編譯,因爲這兩個查詢都是所謂的「微不足道的查詢」,它的編譯成本非常低(即計劃是「明顯的」)。 。即使重新編譯會發生,大多數時候一個壞的計劃(如選項2會創建)比重新編譯更具破壞性。 – 2010-11-04 22:27:07