-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

DB には 100,000 件のレコードはほとんどありませんが、このクエリを実行して 50 件のレコードを取得するのに約 2 秒かかります。まったく受け入れられません!結合が使用されているほとんどの列にインデックスさえあります。

CTE の base 句で単一の結合が行われますが、これは必須です。結合がキラーであることは知っていますが、その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

それは非常に速く実行されます。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 句が決め手です。OldInstrumentIDtype varchar(14) は遅く、2 秒かかりますがd.DocumentID、int 型の which で注文すると、冗長な条件をすべて保持していても 0 秒で正常に動作します。

これは私の実行計画です:

ここに画像の説明を入力

アップデート:

各列にこのようなインデックスを作成しましたが、非常に高速に実行されるようです。ウーウー!!!

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]

)
4

4 に答える 4

1

条件によってクエリが遅くなる理由はいくつか考えられます。

  • クエリエンジンは、インデックスまたはテーブルスキャンを実行して、DocumentsテーブルからDocumentStatusIDの値を取得する以外に選択肢がないのではないかと思います。ただし、私の読書から、条件の最後の行はDocumentStatusIDが常に9に等しくなければならないことを示しているため、この作業の多くは冗長です。SQLServerエンジンがこの条件を最後に処理している場合は、さらに多くのテーブルスキャンを実行している可能性があります。必要以外の条件を評価します。DocumentStatusIDが9のドキュメントのみが返されることに基づいて、他の条件が書き直される可能性があります。
  • CTE内にサブクエリがあり、CTEからの値が要求されるたびに実行されます。AccountsJurisdictionsテーブルが大きく、AccountIDのインデックスが作成されていない場合は、ここでパフォーマンスに影響がある可能性があります。

別の注意点として、「WHERE 1 = 1」ステートメントは、SQL Serverエンジンにすべての行を取得して処理させるため、おそらく削除する必要があります。この構文を使用して、組み込みのクエリ最適化に反対している可能性があります。

于 2012-12-26T15:54:14.527 に答える
1

CTEは、さまざまな方法で簡略化できます。特に、をチェックしてd.DocumentStatusID = 9いるので、他の参照をdocumentStatusId削除できます。

ただし、パフォーマンスの問題は、複雑なロジック inに埋め込まれている句が原因だと思います。多くの場合、SQLServerで非常にうまく最適化されます。ただし、この場合、ネストされたループ結合を取得していると思います。代わりに明示的な結合を実行してみてください。whereIn

    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)でインデックスを作成して、この部分でインデックスが使用されるようにすることもできます。

于 2012-12-26T16:29:55.270 に答える
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

そして、これは必要ですか?
Join Users u on d.UserID = u.UserID
u が FK の場合、これは常に true になります

于 2012-12-26T16:15:51.760 に答える
-1

を作成して、CTE の列として作成し、DocumentstatusID非常に複雑な結合句を最終結合の WHERE として配置します。JurisdictionIDCreatedByJurisdictionID

これらすべての「等しくない」ケースと複雑なロジックで遅くなっていることは驚くことではありません。「等しくない」自体は高速な操作ではないからです。それらの周りのすべてのコードを簡素化しようとしています。

于 2012-12-26T16:07:13.803 に答える