2014-09-10 35 views
0

我有一個緩慢的報告,我發現哪部分查詢速度慢,它與INSERTWHERE子句有關。在這個WHERE條款中有一些使報告變慢的功能。如何提高報告的速度由條款中的ISNULL()函數

這些表使用left joinCshTransBys & CshTransOwners。這些表的某些字段:

  • CshTransBys的列:(PPCodePBCodePCCodeGPCodeGBCodeGCCode,...)。
  • CshTransOwners的列:(PPCodeTOSPBCodeTOSPCCodeTOSGPCodeTOSGBCodeTOSGCCodeTOS,...)。

最後的where條款中有關ISNULL()函數的代碼是:

) or 
    ((@Ptype in (11, 13, 15, 17, 19, 21, 23, 25)) and (isnull(PPCodeTOS,PPCode)<>0)) or 
    ((@Ptype in (12, 13, 16, 17, 20, 21, 24, 25)) and (isnull(PBCodeTOS,PBCode)<>0)) or 
    ((@Ptype in (14, 15, 16, 17, 22, 23, 24, 25)) and (isnull(PCCodeTOS,PCCode)<>0)) or 

    ((@PType=0)and (isnull(PPCodeTOS,PPCode) = @PCode)) or 
    ((@PType=1)and (isnull(PBCodeTOS,PBCode) = @PCode)) or 
    ((@PType=2)and (isnull(PCCodeTOS,PCCode) = @PCode)) 

) 

我的問題是,我怎麼能解決這個問題,我的意思是我該如何擺脫那些isnull()的,由替換別的東西?,在其他地方使用它們?

+0

參數嗅探? – 2014-09-10 08:44:41

+0

按照我的說法,不是「Isnull()」,而是「或」在where子句中影響你的表現。 – AK47 2014-09-10 09:02:02

+0

當我忽略那些IsNull()部分時,速度增加 – user3742119 2014-09-10 09:06:42

回答

0

原因很簡單:dbms很容易找到PPCodeTOS等於@PCode的CshTransOwners中的記錄 - 它可以使用索引。但是,要獲得PPCodeTOS等於@PCode的那些記錄以及PPCodeTOS爲空,但CshTransBys中的PPCode等於@PCode的記錄是另一回事。

詳細說明:這很快:在一個表中查找帶有索引的記錄,然後獲取另一個表的匹配記錄。這很慢:連接兩個表,然後通過首先查看第一個表的列來過濾結果記錄,如果爲null,則查看另一個表的列。

你無法對此做任何事情。這只是它的工作方式。

你可以用PPCodeTOS = @PCode OR (PPCodeTOS IS NULL AND PPCode = @PCode)代替isnull(PPCodeTOS,PPCode) = @PCode,但是這不應該改變任何東西,因爲這與isnull大致相同。那麼,你可以試試。

您還可以添加多餘的標準,並希望這個幫DBMS:

(PPCodeTOS = @PCode OR PPCode = @PCode) AND isnull(PPCodeTOS,PPCode) = @PCode 

但它不太可能要麼有任何效果。有了這麼多的OR,​​dbms不太可能在這裏使用索引。

+0

原因不是索引。那麼它不能使用任何現有的索引。但真正的問題是它必須在所有行上進行幾次計算。所以這就是當沒有索引存在時也會變慢的原因。 – 2014-09-10 09:28:44

+0

這是正確的,順便說一句,我首先檢查是否需要任何索引,因爲它被重新安裝到CshTransBys表中。報告執行耗時4分鐘,現在需要2分鐘。 。這些部件導致查詢是仍然緩慢: (ISNULL(PPCodeTOS,PPCODE)<> 0)) (ISNULL(PBCodeTOS,PBCode)<> 0)) (ISNULL(PCCodeTOS,PCCode)<> 0)) – user3742119 2014-09-10 09:54:28

-1

謝謝你的答案,順便說一句,我首先檢查它是否需要任何索引,因爲它被重新加載到CshTransBys表中。報告執行耗時4分鐘,現在需要2分鐘。 。 這些部分導致查詢仍然緩慢:

(isnull(PPCodeTOS,PPCode)<>0)) 
(isnull(PBCodeTOS,PBCode)<>0)) 
(isnull(PCCodeTOS,PCCode)<>0)) 
2

這歸結爲稱爲SARGability的概念。實質上,因爲您通過標量函數運行列,所以優化器無法知道輸出結果。就你而言,修復很容易;明確你想要如何處理空值。也就是說

Isnull(a, b) =0 

假作

(a=0 or (a is null and b=0)) 
+0

想知道爲什麼查詢優化器不這樣做? – Paparazzi 2014-09-11 15:59:56

+0

它肯定會很好,呃?特別是對於這個特殊情況,它並不像其他地方不存在重寫規則...... – 2014-09-11 17:51:57

0

我想你一定可以修剪下來

or 
    (
     (@Ptype in (11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 24, 25)) 
     and (PBCodeTOS<>0 or (PBCodeTOS is null and PBCode<>0)) 
     -- and (isnull(PBCodeTOS,PBCode)<>0) 
    ) 
    or 
    (
     (@PType in (0,1,2)) 
     and (PBCodeTOS<>0 or (PBCodeTOS is null and PBCode<>0)) 
     -- and (isnull(PBCodeTOS,PBCode)<>0) 
    ) 

查詢

(
     (@Ptype in (11, 13, 15, 17, 19, 21, 23, 25)) 
     and (isnull(PPCodeTOS,PPCode)<>0) 
    ) 
    or 
    (
     (@Ptype in (12, 13, 16, 17, 20, 21, 24, 25)) 
     and (isnull(PBCodeTOS,PBCode)<>0) 
    ) 
    or 
    (
     (@Ptype in (14, 15, 16, 17, 22, 23, 24, 25)) 
     and (isnull(PCCodeTOS,PCCode)<>0) 
    ) 
    or 
    (
     (@PType=0) 
     and (isnull(PPCodeTOS,PPCode) = @PCode) 
    ) 
    or 
    (
     (@PType=1) 
     and (isnull(PBCodeTOS,PBCode) = @PCode) 
    ) 
    or 
    (
     (@PType=2) 
     and (isnull(PCCodeTOS,PCCode) = @PCode) 
    ) 
0

ISNULLSARGEABLE。 SQL Server不知道哪些行滿足條件isnull(PPCodeTOS,PPCode)<>0,因此它必須將ISNULL應用於所有行,然後過濾掉結果集。在這種情況下索引是無用的。

更換ISNULL有明確檢查空值:

or 
    (@Ptype in (11, 13, 15, 17, 19, 21, 23, 25) and ((PPCodeTOS IS NOT NULL and PPCodeTOS <> 0) or (PPCodeTOS IS NULL and PPCode <> 0))) or 
    (@Ptype in (12, 13, 16, 17, 20, 21, 24, 25) and ((PBCodeTOS IS NOT NULL and PBCodeTOS <> 0) or (PBCodeTOS IS NULL and PBCode <> 0))) or 
    (etc.) 

它看起來更詳細,但如果速度是十有二#1的關注,這可能會有幫助。