3

ページングと順序付けを行いたいテーブルがあり、次のようなクエリを取得して作業を行うことができました (実際のクエリは、結合などにはるかに関与しています)。

WITH NumberedPosts (PostID, RowNum) AS
(
    SELECT PostID, ROW_NUMBER() OVER (ORDER BY
        CASE WHEN @sortCol = 'User' THEN User END DESC,
        CASE WHEN @sortCol = 'Date' THEN Date END DESC,
        CASE WHEN @sortCol = 'Email' THEN Email END DESC) as RowNum
   FROM Post
)
INSERT INTO #temp(PostID, User, Date, Email)
SELECT PostID, User, Date, Email
FROM Post
WHERE NumberedPosts.RowNum BETWEEN @start and (@start + @pageSize)
      AND NumberedPosts.PostID = Post.PostID

ORDER BY Date desc問題は、CASE ステートメントを使用すると、通常の句と比較してパフォーマンスが大幅に低下することです (少なくとも 10 倍の速度低下) 。クエリ プランを見ると、@sortCol 修飾子と一致しない場合でも、すべての列がまだ並べ替えられているように見えます。

これを「ネイティブ」に近い速度で実行する方法はありますか? 動的 SQL はこの問題の最良の候補ですか? ありがとう!

4

4 に答える 4

3

3 つのハードコーディングされたクエリ (@sortCol に基づく適切な IF ステートメント) または動的 SQL を使用してこれを行うことをお勧めします。

3 つの異なるクエリ (すべての JOIN を実行する基本 CTE に基づく) の UNION ALL を使用してトリックを実行できる場合があります。ここでは、1 つだけが @sortCol の行を返しますが、推奨する前にプロファイリングする必要があります。

WITH BasePosts(PostID, User, Date, Email) AS (
    SELECT PostID, User, Date, Email
    FROM Posts -- This is your complicated query
)
,NumberedPosts (PostID, User, Date, Email, RowNum) AS
(
    SELECT PostID, User, Date, Email, ROW_NUMBER() OVER (ORDER BY User DESC)
    FROM BasePosts
    WHERE @sortCol = 'User'

    UNION ALL

    SELECT PostID, User, Date, Email, ROW_NUMBER() OVER (ORDER BY Date DESC)
    FROM BasePosts
    WHERE @sortCol = 'Date'

    UNION ALL

    SELECT PostID, User, Date, Email, ROW_NUMBER() OVER (ORDER BY Email DESC)
    FROM BasePosts
    WHERE @sortCol = 'Email'
)
INSERT INTO #temp(PostID, User, Date, Email)
SELECT PostID, User, Date, Email
FROM NumberedPosts
WHERE NumberedPosts.RowNum BETWEEN @start and (@start + @pageSize)
于 2010-07-13T00:02:12.727 に答える
3

post テーブルを 2 回クエリする必要はありません。動的な方法でパフォーマンスの問題に対処するか、@sortCol パラメータで決定される 3 つのクエリを作成できます。row_num と order by パーツ以外の冗長なコードですが、速度が重要な場合は保守性をあきらめることがあります。

If @sortCol = 'User' 
Begin
  Select... Order by User
End

If @sortCol = 'Date' 
Begin
  Select .... Order by Date 
end

If @sortCol = 'Email' 
Begin
  Select... Order by Email
End 
于 2010-07-13T00:55:03.223 に答える
2

私は間違いなく動的 SQL ルートをたどります (インジェクション攻撃を回避するためにパラメーターを指定して sp_executesql を使用します)。CASE アプローチを使用すると、SQL Server が並べ替えプロセスに役立つ関連インデックスをすぐに使用できなくなります。

于 2010-07-13T00:01:49.960 に答える
0

これは機能するはずですが、パフォーマンスが向上するかどうかはわかりません。

WITH NumberedPosts (PostID, RowNum) AS
(
    SELECT PostID, ROW_NUMBER() OVER (ORDER BY
        CASE WHEN @sortCol = 'User' THEN User 
             WHEN @sortCol = 'Date' THEN Date
             WHEN @sortCol = 'Email' THEN Email
        END DESC) as RowNum
   FROM Post
)
INSERT INTO #temp(PostID, User, Date, Email)
SELECT PostID, User, Date, Email
FROM Post
WHERE NumberedPosts.RowNum BETWEEN @start and (@start + @pageSize)
      AND NumberedPosts.PostID = Post.PostID
于 2010-07-13T02:54:30.410 に答える