2

これは、SSMS で約 300 ~ 400 ミリ秒のミリ秒単位で実行される検索フォームで使用される動的クエリです。

exec sp_executesql N'set arithabort off;
set transaction isolation level read uncommitted;

With cte as 
  (Select ROW_NUMBER() OVER 
      (Order By  Case When d.OldInstrumentID IS NULL 
          THEN d.LastStatusChangedDateTime Else d.RecordingDateTime End 
       desc) peta_rn,   
      d.DocumentID
   From Documents d
   Inner Join Users u on d.UserID = u.UserID 
   Inner Join IGroupes ig on ig.IGroupID = d.IGroupID
   Inner Join ITypes it on it.ITypeID = d.ITypeID 
   Where 1=1  
       And (CreatedByAccountID = @0 Or DocumentStatusID = @1 Or DocumentStatusID = @2 )  
       And (d.JurisdictionID = @3 Or DocumentStatusID = @4 Or DocumentStatusID = @5)   
       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,ig.Abbreviation as IGroupAbbreviation, 
    u.Username, j.JDAbbreviation, inf.DocumentName,
    it.Abbreviation as ITypeAbbreviation, d.DocumentDate, 
    ds.Abbreviation as DocumentStatusAbbreviation,
    Upper(dbo.GetFlatDocumentName(d.DocumentID)) as FlatDocumentName 
From Documents d 
Left Join IGroupes ig On d.IGroupID = ig.IGroupID 
Left Join ITypes it On d.ITypeID = it.ITypeID 
Left Join Users u On u.UserID = d.UserID 
Left Join DocumentStatuses ds On d.DocumentStatusID = ds.DocumentStatusID 
Left Join InstrumentFiles inf On d.DocumentID = inf.DocumentID 
Left Join Jurisdictions j on j.JurisdictionID = d.JurisdictionID 
Inner Join cte on cte.DocumentID = d.DocumentID 
Where 1=1 
    And peta_rn>=@6 AND peta_rn<=@7 
Order by peta_rn',
N'@0 int,@1 int,@2 int,@3 int,@4 int,@5 int,@6 bigint,@7 bigint',
@0=44,@1=5,@2=9,@3=1,@4=5,@5=9,@6=94200,@7=94250

この SQL は C# コードで作成され、ユーザーが検索フォームで検索した値に基づいて where 句が動的に追加されます。1 ページから 2 ページに移動するのに約 3 秒かかります。検索するほとんどの列に必要なインデックスが既にあります。

なぜ私の Ado.Net コードが遅いのでしょうか?

更新:実行計画が役立つかどうかはわかりませんが、ここにあります:

ここに画像の説明を入力

ここに画像の説明を入力

ここに画像の説明を入力

4

3 に答える 3

1

SQL サーバーが ADO​​.NET 接続に対して不適切なクエリ プランを作成した可能性があります。ADO で同様の問題が発生しました。通常の解決策は、すべてのクエリ プランをクリアして低速クエリを再度実行することです。これにより、より適切なプランが作成される場合があります。クエリ プランをクリアするには、関連するテーブルの統計を更新するのが最も一般的な解決策です。次のように:

update statistics documents with fullscan

関連する他のテーブルについても同じことを行い、ADO.NET から遅いクエリを実行します (以前に SSMS を実行しないでください)。

このようなタイミングの不一致は、クエリまたはデータベースの設計が悪いことを示唆している可能性があることに注意してください-少なくとも私たちにとっては、通常そうです:)

于 2013-03-01T09:21:33.957 に答える
0

SSMS でクエリを繰り返し実行すると、データベースは以前に作成された実行プランを再利用し、必要なデータが既にメモリにキャッシュされている可能性があります。

あなたのクエリで気づいたことがいくつかあります。

  • CTE は Users、IGroupes、および ITypes を結合しますが、結合されたレコードは SELECT で使用されません

  • CTE は、計算された式で ORDER BY を実行します ((インデックスなし) ソートの 85% のコストに注意してください)

おそらく、CASE 式を、インデックス付けできる計算された永続化された列に置き換えると、実行速度が向上します。

  • ORDER BY は、4 つのテーブルを結合した結果のデータに対して実行されることに注意してください。

  • CTE の WHERE 条件は を示していますAND d.DocumentStatusID = 9が、AND の他の DocumentStatusIDs

  • ページングは​​、JOIN された 8 つのテーブルの結果に対して実行されます。

peta_rnほとんどの場合、パフォーマンスの向上に基づいて最初の CTE をフィルタリングする中間 CTE を作成します。

于 2013-03-01T09:05:06.130 に答える
0

.net はデフォルトで UTF 文字列を使用します。これは、VARCHAR ではなく NVARCHAR と同等です。

dot net で WHERE ID = @foo を実行している場合、暗黙的に実行している可能性があります。

WHERE CONVERT(ID, NVARCHAR) = @foo

その結果、この where 句にインデックスを付けることができず、テーブルをスキャンする必要があります。解決策は、DbType が VARCHAR に設定された DbParameter として各パラメーターを実際に SqlCommand に渡すことです (文字列の場合)。

もちろん、.net パラメータが同等の SQL 列よりも「広い」場合、同様の状況が Int 型で発生する可能性があります。

PSこの問題を「証明」する最も簡単な方法は、上記の次のようにSSMSでクエリを実行することです

DECLARE @p0 INT = 123
DECLARE @p1 NVARCHAR = "foobar" //etc etc

と比較して

DECLARE @p0 INT = 123
DECLARE @p1 VARCHAR = "foobar" //etc etc
于 2013-03-01T08:27:52.707 に答える