0

ロジック間のいくつかを使用してデータのチャンクを戻すストアド プロシージャがあります。私のステートメントの PostFamilyTags テーブルには、約 150 万行あります。以下の sql ステートメントは非常に遅く実行されます。

SELECT TOP(100)*  FROM
    (SELECT ROW_NUMBER() 
        OVER(ORDER BY p.date  DESC) as NUM,    
        m.postfamilymediaID, 
        m.postfamilyID, 
        p.blogID,
        p.userID, 
        p.BlogPostID, 
        m.postfamilymediatypeID as Type, 
        p.Title, 
        m.Address, 
        m.AddressEncoded, 
        m.ThumbNailAddress, 
        p.Date, 
        p.Summary, 
        p.Url, 
        m.ThumbNailIndex, 
        m.ThumbNailHeight, 
        m.ThumbNailWidth, 
        m.ThumbNailHeightAlt, 
        m.ThumbNailWidthAlt, 
        m.ItemName, 
        m.id3Title, 
        m.id3SubTitle, 
        m.id3ContributingArtists, 
        m.id3AlbumArtist, 
        m.id3Album, 
        m.id3Year, 
        m.id3Genre, 
        m.id3Length, 
        m.IsPublic      
FROM         
        PostFamilyMedia as m
        inner join 
        PostFamily as p on m.postfamilyID = p.postfamilyID 
        inner join 
        PostFamilyTags as pt on p.postfamilyID = pt.postfamilyID 
        inner join --Tags
        Tags as t on pt.tagID = t.tagID 
        Where t.TagLevel = 1 and t.Tag = 'Electronic' 
) AS a  WHERE NUM >= (100 + 1)  AND NUM <= (100 + 100)

しかし、その間のロジックを取り除くと、うまく機能します。

SELECT TOP(100)
        m.postfamilymediaID, 
        m.postfamilyID, 
        p.blogID,
        p.userID, 
        p.BlogPostID, 
        m.postfamilymediatypeID as Type, 
        p.Title, 
        m.Address, 
        m.AddressEncoded, 
        m.ThumbNailAddress, 
        p.Date, 
        p.Summary, 
        p.Url, 
        m.ThumbNailIndex, 
        m.ThumbNailHeight, 
        m.ThumbNailWidth, 
        m.ThumbNailHeightAlt, 
        m.ThumbNailWidthAlt, 
        m.ItemName, 
        m.id3Title, 
        m.id3SubTitle, 
        m.id3ContributingArtists, 
        m.id3AlbumArtist, 
        m.id3Album, 
        m.id3Year, 
        m.id3Genre, 
        m.id3Length, 
        m.IsPublic      
FROM         
        PostFamilyMedia as m
        inner join 
        PostFamily as p on m.postfamilyID = p.postfamilyID 
        inner join 
        PostFamilyTags as pt on p.postfamilyID = pt.postfamilyID 
        inner join --Tags
        Tags as t on pt.tagID = t.tagID 
        Where t.TagLevel = 1 and t.Tag = 'Electronic' 

最初の sql ステートメントの実行を高速化するのを手伝ってくれる人はいますか?

4

3 に答える 3

1

どちらの Tags テーブルからも列を選択していないため、これを記述する別の方法があります。

Select Top(100)
  *
From (
  Select
    Row_Number() Over (Order By p.date Desc) as Num,
    m.postfamilymediaID,
    m.postfamilyID,
    m.postfamilymediatypeID as Type, 
    p.Title, 
    p.Date -- and the rest of the fields
  From
    PostFamilyMedia As m
      Inner Join 
    PostFamily As p On m.postfamilyID = p.postfamilyID 
  Where
    Exists (
      Select 
        'x'
      From 
        Tags As t 
          Inner Join
        PostFamilyTags As pt 
          On pt.tagID = t.tagID 
      Where
        t.TagLevel = 1 and
        t.Tag = 'Electronic' And
        p.postfamilyID = pt.postfamilyID
      )
  ) As a
Where
  Num >= (100 + 1) And Num <= (100 + 100);

http://sqlfiddle.com/#!3/e073d/1のいくつかの非常に基本的なテストでは、このように記述すると、日付列にカバリング インデックスが使用されますが、現在の方法では使用されません。これがより大きなボリュームで当てはまるかどうか (およびパフォーマンスがまったく向上するかどうか) は、テストが必要です。

また、PostFamilyTags (PostFamilyID, TagID)ユニークだと思います。この種のクエリは、一意のインデックスを定義する順序に影響されます。どちらが最適かを判断する最も簡単な方法は、両方を作成し、オプティマイザーが何を選択するかを確認することです。TagID, PostFamilyID少量の場合に最適に機能するようです。

が一意の場合Tags (TagLevel, Tag)、別のクエリで一意の TagID を読み取ってから、メイン クエリからタグを削除できます。タグは他のテーブルに比べて小さい可能性が高いため、これが大きな影響を与えるとは思えません。

Declare @TagID int
Select
  @TagID = TagID
From
  Tags
Where
  TagLevel = 1 And
  Tag = 'Electronic'

Select Top(100)
  *
From (
  Select
    Row_Number() Over (Order By p.date Desc) as Num,
    m.postfamilymediaID,
    m.postfamilyID,
    m.postfamilymediatypeID as Type, 
    p.Title, 
    p.Date -- and the rest of the fields...
  From
    PostFamilyMedia As m
      Inner Join 
    PostFamily As p On m.postfamilyID = p.postfamilyID 
  Where
    Exists (
      Select 
        'x'
      From 
        PostFamilyTags As pt 
      Where
        p.postfamilyID = pt.postfamilyID And
        pt.TagID = @TagID
      )
  ) As a
Where
  Num >= (100 + 1) And Num <= (100 + 100);

PostFamilyMediaマッチングごとにすべてを選択しているため、主キーの代わりにPostFamily最初のテーブルをクラスター化することで速度が向上する場合があります。PostFamilyID, PostFamilyMediaID2 番目の列は、一意にするために含まれています。SQL Server は、非一意のクラスター化インデックスに非表示の一意の値を追加します。トレードオフは、アプリの別の部分が個々のレコードを選択する場合、少し遅くなるということです。別のカバリング インデックスを使用すると、挿入と更新が遅くなりますが、両方を高速に取得できます。

于 2013-01-13T02:10:38.463 に答える
0

あなたの質問に直接答えるために; 最初のクエリを高速化するための私のアプローチは、table.column(order)にインデックスを付けることです。**PostFamily.date DESC**

私がこれを言う理由は、([Num]に基づいて)データをページングする必要があるように見えるからです。人々が指摘しているように、このROW_NUMBER()操作では、修飾するすべての行を読み取る必要があります。ただし、読み取る必要があるだけでなく、並べ替える必要もあります。特に大規模なデータセットでは、並べ替えは非常にコストがかかります。私が説明したように、インデックスがこれに役立つことを願っています。

2つのクエリの違いを説明するために、アナロジーを提供できます。次のリストがあるとします。

Mike
Susan
Andrew
Felicity
George
Laura
Ben
Robert
Julia
Jim
Kath
  1. トップ3の名前を教えてください
  2. アルファベットの逆順で上位3つの名前を教えてください

これらの2つのタスクのうち、より多くの作業が必要になるのはどれですか。

于 2013-01-13T05:29:23.683 に答える
0

問題は、「速い」と「遅い」と考えるものかもしれません。クエリが数百万行を返す可能性がある場合、多くの場合、最初の行までの時間がクエリの長​​さとして使用されているようです。ただし、最後の行までの時間を考慮する必要があります。

関数を追加することによりrow_number、SQL は行を返す前に結果セット全体を生成する必要があります。遅いように見えますが、結果セット全体の時間を測定すると、それほど遅くはありません ( のせいで少しだけrow_number())。

row_number()サブクエリで実行することで、これを高速化できる場合があります。

from (select row_number() order by pdate) . . .
      from PostFamily p
     )

そして、on句に条件を含めます。

索引付けを賢明に使用すると役立つ場合があります。テーブルのインデックスに pdate がありますか? ただし、これが役立つかどうかはわかりません。

于 2013-01-13T00:16:30.297 に答える