2012-12-26 96 views
-3

這是我的查詢:慢速查詢執行效率

With cte as (
    Select 
     ROW_NUMBER() OVER (Order By d.OldInstrumentID) peta_rn, 
     d.DocumentID 
    From Documents d 
    Inner Join Users u on d.UserID = u.UserID 
    Where 1=1 
     And (d.JurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9) 
     And d.DocumentStatusID <> 3 And d.DocumentStatusID <> 8 
     And d.DocumentStatusID <> 7 
     AND ((CreatedByJurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9 Or CreatedByAccountID IN (Select AccountID From AccountsJurisdictions Where JurisdictionID = 1))) 
     And d.DocumentStatusID = 9 
) 
Select 
    d.DocumentID, 
    d.IsReEfiled, 
    d.IGroupID, 
    d.ITypeID, 
    d.RecordingDateTime, 
    d.CreatedByAccountID, 
    d.JurisdictionID, 
    Case 
     When d.OldInstrumentID IS NULL 
     THEN d.LastStatusChangedDateTime 
     Else d.RecordingDateTime 
    End as LastStatusChangedDateTime, 
    dbo.FnCanChangeDocumentStatus(d.DocumentStatusID,d.DocumentID) as CanChangeStatus, 
    d.IDate, 
    d.InstrumentID, 
    d.DocumentStatusID, 
    d.DocumentDate, 
    Upper(dbo.GetFlatDocumentName(d.DocumentID)) as FlatDocumentName 
From Documents d 
Inner Join cte on cte.DocumentID = d.DocumentID 
Where 1=1 
    And peta_rn>=80000 
    AND peta_rn<=80050 
Order by peta_rn 

有幾乎10萬條記錄的數據庫,但此查詢需要約2秒鐘來執行去取僅有50條記錄。完全不能接受!我甚至在大多數使用連接的列上都有索引。

單個連接是在CTE的基礎子句中進行的,但這是必需的。我知道加入是殺手,但我需要加入。如果刪除這段代碼:

And (d.JurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9) 
And d.DocumentStatusID <> 3 
And d.DocumentStatusID <> 8 
And d.DocumentStatusID <> 7 
AND ((CreatedByJurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9 Or CreatedByAccountID IN (Select AccountID From AccountsJurisdictions Where JurisdictionID = 1))) 
And d.DocumentStatusID = 9 

它運行速度非常快。在SSMS中顯示0秒。任何方式來加快這個查詢?我需要這些條件,他們甚至不是那麼大。爲什麼條件會減慢查詢速度?我已經在CreatedByAccountID和其他列上有索引。真煩人!

編輯:

感謝您的答覆。一些更多細節:

你們許多人建議刪除多餘的條件。對不起,這段SQL是在代碼中動態生成的,我在SSMS和這裏粘貼了這個版本。從where子句中刪除這些條件並沒有幫助:

Where 1=1 
    And (d.JurisdictionID = 1 Or d.DocumentStatusID = 5 Or d.DocumentStatusID = 9) 
    And d.DocumentStatusID <> 3 
    And d.DocumentStatusID <> 8 
    And d.DocumentStatusID <> 7 
    AND ((CreatedByJurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9 Or CreatedByAccountID IN (Select AccountID From AccountsJurisdictions Where JurisdictionID = 1))) 
    And d.DocumentStatusID = 9 

事實上,儘快我把where子句放慢了速度。所以,即使這一個很慢:

Where 1=1 
    And (d.JurisdictionID = 1 Or d.DocumentStatusID = 5 Or d.DocumentStatusID = 9) 

一些更多的細節。 Row_Number()中的order by子句是決定因素。 OldInstrumentID這是類型varchar(14)的速度很慢,需要2秒,而如果我通過d.DocumentID命令的類型爲int,它在0秒內工作正常,即使我保留所有這些冗餘條件。

這是我的執行計劃:

enter image description here

更新:

我創建的索引像這樣在每個柱,它似乎運行超級快。 Woot Woot !!!

Create NonClustered Index IX_DocumentDate on Documents 
(
    DocumentDate  

) 
Include(
    JurisdictionID, 
    JudgementTypeID, 
    IDate, 
    EfileDate, 
    UserID, 
    RecordingDateTime, 
    ApprovedBy, 
    ACEfileBankAccountID, 
    LastStatusChangedDateTime, 
    ACEfileCreditCardID, 
    EfiledByUserID, 
    ITypeID, 
    IGroupID, 
    InstrumentID, 
    OldInstrumentID, 
    [CreatedByJurisdictionID], 
    CreatedByAccountID, 
    [DocumentStatusID]  


     ,[Remarks] 
     ,[InternalNotes] 
     ,[ParentDocumentID] 
     ,[FilingNumber] 
     ,[StampData]  
     ,[Receipt] 
     ,[ReceiptNo] 
     ,[IsReEfiled]  
     ,[ImportedFromInstrumentID] 

) 
+2

你能發佈執行計劃嗎? – SWeko

+0

它在我看來''where'有太多的條件,但是如果d.DocumentStatusID不等於9,它們都會失敗9.對不起,很難閱讀這樣的查詢(你只在某些地方使用表別名 - 某處它是'd.DocumentStatusID',在其他地方是'DocumentStatusID' – a1ex07

+3

在國際論壇上發佈問題時,最好避免使用高度區域化的詞語,如「lac」或「lakh」。更常規的詞語是100,000。 –

回答

1

有幾個可能的原因是,條件可以查詢減緩:

  • 我懷疑查詢引擎別無選擇,只能執行索引或表掃描得到的值Document表中的DocumentStatusID。但是,從我的閱讀中,大部分工作都是多餘的,因爲條件的最後一行指出DocumentStatusID必須始終等於9.如果SQL Server引擎最後處理此情況,則可能是它正在執行更多的表掃描評估其他條件,而不是它需要的。可能會重新編寫您的其他條件,因爲您將只擁有返回DocumentStatusID爲9的文檔。
  • CTE中有一個子查詢,每次請求CTE的值時都會執行這個子查詢。如果AccountsJurisdictions表很大並且AccountID沒有編入索引,那麼這裏可能會有性能影響。

正如另一個說明,應該刪除「WHERE 1 = 1」語句,因爲它們將強制SQL Server引擎檢索並處理所有行,我認爲 - 您可能會使用內置查詢使用此語法進行優化。

+1

如果引擎在查詢中沒有刪除WHERE 1 = 1,那麼我會很驚訝重寫ph酶。 – DeanGC

-1

我會嘗試使DocumentstatusID,JurisdictionIDCreatedByJurisdictionID作爲CTE中的列,並將非常複雜的連接子句作爲最後連接處的WHERE。

對於所有'不等於'情況和複雜邏輯,我並不感到驚訝,因爲'不等於'本身不是一個快速操作。我試圖簡化所有這些代碼。

+0

移動到哪裏,那麼ROW_NUMBER將不會相同。 – Paparazzi

+0

@Scott Earle:如果你把最終的連接放在哪裏,你將如何獲得row_number的正確編號? – Jack

0

如果d.DocumentStatusID = 9,然後大量的冗餘條件

;With cte as (
       Select ROW_NUMBER() OVER (Order By d.OldInstrumentID) peta_rn, d.DocumentID 
       From Documents d 
       Join Users u 
        on d.UserID = u.UserID 
       Where -- 1 = 1 AND 
       d.DocumentStatusID = 9 
       AND (CreatedByJurisdictionID = 1 
        Or CreatedByAccountID IN (Select AccountID From AccountsJurisdictions Where JurisdictionID = 1) 
        ) 
       -- below redundant as d.DocumentStatusID = 9 
       --(d.JurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9) 
       --And d.DocumentStatusID <> 3 
       --And d.DocumentStatusID <> 8 
       --And d.DocumentStatusID <> 7 
       --AND (
       --  Or DocumentStatusID = 5 
       --  Or DocumentStatusID = 9 
       -- ) 
      ) 
Select d.DocumentID, d.IsReEfiled, d.IGroupID, d.ITypeID, d.RecordingDateTime -- ... 
From Documents d 
Join cte 
    on cte.DocumentID = d.DocumentID 
Where -- 1=1 AND 
    peta_rn>=80000 AND peta_rn<=80050 
Order by peta_rn 

,是這甚至是必要的?
加入用戶U ON d.UserID = u.UserID
如果u是一個FK那麼這將永遠是真正的

+0

請閱讀我的編輯。 – Jack

+0

其中一個查詢不是「有效編寫」的,兩個如果您無法更改查詢,則應該在原始問題中包含該查詢。 – Paparazzi

1

你的CTE可以通過多種方式來簡化。特別是,您正在檢查d.DocumentStatusID = 9,因此可以刪除對documentStatusId的任何其他參考。

但是,我認爲性能問題是由於複雜的where邏輯中嵌入了in子句。 In在SQL Server中經常優化得非常好。不過,在這種情況下,我猜你正在得到一個嵌套的循環連接。嘗試這樣做,而不是顯式連接:

Select ROW_NUMBER() OVER (Order By d.OldInstrumentID) peta_rn, 
      d.DocumentID 
    From Documents d Inner Join 
     Users u left outer join 
     on d.UserID = u.UserID 
     (select distinct AccountId 
      from AccountsJurisdictions 
      Where JurisdictionID = 1 
     ) aj1 
     on u.CreatedByAccountID = aj1.AccountId and 
       (d.JurisdictionID = 1 Or DocumentStatusID = 5 Or DocumentStatusID = 9) AND 
       d.DocumentStatusID <> 3 And d.DocumentStatusID <> 8 AND 
       d.DocumentStatusID <> 7 AND 
       (CreatedByJurisdictionID = 1 Or DocumentStatusID = 5 
       Or DocumentStatusID = 9 Or aj1.AccountId is not NULL 
       ) AND 
       d.DocumentStatusID = 9 

您也可以嘗試在AccountsJurisdictions(JurisdictionId, AccountId)因此指數被用於這一部分創建一個索引。

+0

請閱讀我的編輯。 – Jack

+0

您使用*的語法(從帳戶管轄區域中選擇不同的AccountId 其中JurisdictionID = 1 )aj1 *不正確(至少在SQL Server中)。查詢不是編譯。 – Jack

+0

顯然,我錯誤地將「WHERE」留在了那裏。我也刪除了「1 = 1」。 –