2009-12-20 38 views
3

不知道從哪一個開始這一個 - 不知道是否問題是我愚弄查詢優化器,或者如果它是內在的當涉及到空值時指標的工作方式。SQL Server查詢優化:其中(Col = @ Col或@ Col = Null)

一個編碼約定,我跟着是編寫像這樣的存儲過程:當你想要一個存儲過程來

declare procedure SomeProc 
    @ID int = null 
as 
    select 
    st.ID,st.Col1,st.Col2 
    from 
    SomeTable st 
    where 
    (st.ID = @ID or @ID is null) --works, but very slow (relatively) 

這不是說簡單的測試用例是非常有用的,當然,但在其他情況下非常有用在滿足某些條件的整個表或行上進行操作。然而,更大的表使用時...大約提升3至5慢於如果我換成where子句這是相當緩慢:

where 
    st.ID = @ID --3-5x faster than first example 

我甚至用事實與更換空更不解-1讓我幾乎相同的速度「固定」 WHERE子句上面:

declare procedure SomeProc 
    @ID int = -1 
as 
    select 
    st.ID,st.Col1,st.Col2 
    from 
    SomeTable st 
    where 
    (st.ID = @ID or @ID=-1) --much better... but why? 

顯然,這是一個的把事情古怪,但爲什麼,到底空?從審查執行計劃來看,我的答案並不明確。這是我多年來在SQL Server的各種數據庫,表和版本上注意到的,所以我不認爲這是我當前環境的一個怪癖。 我通過將默認參數值從null切換到-1來解決問題;我的問題是爲什麼這個工程。

  1. SomeTable.ID被索引
  2. 這可能與(或可能,其實是)一個參數嗅探問題 Parameter Sniffing (or Spoofing) in SQL Server 不管它的價值,我已經 測試幾乎完全與 「exec SomeProc」後每個 編輯/重新編譯的過程,即與 的可選參數省略。

回答

6

你的問題相結合,最有可能的

  1. 參數嗅探
  2. 或不是一個很好的經營者使用

但是,如果沒有看到這些計劃,這些都是猜測。

參數嗅探

...默認的 「空」 的。試用不同的默認值,比如說-1或者沒有默認值。

@ID = -1,默認值爲NULL,參數嗅探=平凡檢查,所以速度更快。

您也可以嘗試OPTIMISE FOR UNKNOWN在SQL Server 2008

OR操作符

一些想法..

如果列不可爲空,在大多數情況下,優化器會忽略的條件

st.ID = ISNULL(@ID, st.ID) 

而且,你都可以採用類似的方式使用IF語句

IF @ID IS NULL 
    SELECT ... FROM... 
ELSE 
    SELECT ... FROM... WHERE st.ID 

或聯合。

就個人而言,我會使用在大多數情況下,參數屏蔽(總是)和ISNULL(我第一次嘗試)

alter procedure SomeProc 
    @ID int = NULL 
AS 
declare @maskID int 
select @maskID = @ID 
... 
+0

感謝偉大的答覆。我懷疑這是最重要的。我很無知OR的代價如何。最後,在提示之後,爲了便於閱讀,我使用存儲過程頂部的SET @ ID = ISNULL(@ ID,-1)。 (實際存儲的過程相當長,我不想在裏面埋藏「默認」)再次感謝。 –

相關問題