SQL ServerのROW_NUMBERでページングは​​どのように機能しますか?


13

Employee100万件のレコードを持つテーブルがあります。Webアプリケーションでデータをページングするための次のSQLがあります。正常に動作しています。しかし、私が問題と思うのは、派生テーブルtblEmployeeEmployeeテーブル内のすべてのレコードを選択することMyRowNumberです(値を作成するため )。

これにより、Employeeテーブル内のすべてのレコードが選択されると思います。

それは本当にうまくいくのでしょうか?または、SQL Serverは元のEmployeeテーブルから5つのレコードのみを選択するように最適化されていますか?

DECLARE @Index INT;
DECLARE @PageSize INT;

SET @Index = 3;
SET @PageSize = 5;

SELECT *  FROM
  (SELECT  ROW_NUMBER() OVER (ORDER BY EmpID asc) as MyRowNumber,*
  FROM Employee) tblEmployee
WHERE MyRowNumber BETWEEN ( ((@Index - 1) * @PageSize )+ 1) AND @Index*@PageSize 

3
sqlservercentral.com/articles/T-SQL/66030を参照してください。さらに重要なことは、次の議論を参照してください。
アーロンバートランド

回答:


17

テストの代替手段は次のとおりです。

;WITH x AS (SELECT EmpID, k = ROW_NUMBER() OVER (ORDER BY EmpID) FROM dbo.Emp)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
WHERE x.k BETWEEN (((@Index - 1) * @PageSize) + 1) AND @Index * @PageSize
ORDER BY ...;

はい、テーブルに2回ヒットしますが、テーブル全体をスキャンするCTEでは、すべてのデータではなく、キーのみを取得しています。しかし、あなたは本当にこの記事を見るべきです:

http://www.sqlservercentral.com/articles/T-SQL/66030/

そして、フォローアップの議論:

http://www.sqlservercentral.com/Forums/Topic672980-329-1.aspx

もちろん、SQL Server 2012では、新しいOFFSET/ FETCH NEXT構文を使用できます。

;WITH x AS 
(
  SELECT EmpID FROM dbo.Emp
    ORDER BY EmpID
    OFFSET  @PageSize * (@Index - 1) ROWS
    FETCH NEXT @PageSize ROWS ONLY
)
SELECT e.columns
FROM x INNER JOIN dbo.Emp AS e
ON x.EmpID = e.EmpID
ORDER BY ...; 

ただし、OFFSET / FETCH NEXTはCTE方式よりもパフォーマンス上の利点がありません。
アカシュ

2
@Akashはこれを徹底的にテストしましたか?私はいくつかの計画の違いを観察しましたが、大規模なテストを行っていないため、パフォーマンスについては特に言及しませんでした。パフォーマンスが同じでも、構文は少し面倒ではありません。私はここでそれについてのブログでした:sqlblog.com/blogs/aaron_bertrand/archive/2010/11/10/...
アーロン・ベルトラン

1
ああ、あなたは正しい、パフォーマンスの違いがあります。私はこれを読んでいました:blogs.technet.com/b/dataplatforminsider/archive/2011/11/01 / ...彼は違いを言及していませんが、彼がそこに示すところにchannel9.msdn.com/posts/SQL11UPD03-REC-02をました多くの違い..(ただし、オーディオの強調はパフォーマンスの違いですが)
-Akash

2

その背後にあるメカニズムを知らないかもしれませんが、クエリのパフォーマンスを次のように比較することで、あなた自身でこれをテストできます:select * from Employee。

SQL Serverの最新バージョンは最適化のかなり良い仕事をしますが、いくつかの要因に依存します。

ROW_NUMBER関数の実行方法は、Order By句によって決まります。あなたの例では、ほとんどがEmpIDが主キーであると推測します。

いくつかありますので、複雑かつ/または不十分なコード化されたか、インデックス付けされている条項は、あなただけのデータセット全体を(それは稀だと固定することができます)戻ったほうが良いかもしれません。BETWEENの使用には問題があります。

すべての行をアプリケーションに返し、それを把握する方がよいと考える前に、クエリの最適化に取り組む必要があります。見積もりを確認してください。クエリアナライザーに問い合わせます。いくつかの選択肢をテストします。


2

row_number()に関する質問であることは知っていますが、SQL Server 2012の新しい機能を1つ追加したいと思います。SQLServer 2012では、OFFSET Fetchが次に導入され、row_number()よりも高速です。私はそれを使用しました、そして、それはあなたたちも同じ経験を満たしてくれることを望みます。

http://blogfornet.com/2013/06/sql-server-2012-offset-use/で 1つの例を見つけました

これは便利です。新しい機能の実装にも役立つことを願っています。


-2

元のテーブルのすべての行を返すと評価されるとは思わない。SQLサーバーが最適化します。そうしないと、100万のエントリを選択するのに膨大な時間がかかります。現在これを使用していますが、すべての行を選択するよりもはるかに高速です。したがって、すべての行を取得するわけではありません。ただし、おそらく順序付けに時間がかかるため、最初の5行をフェッチするよりも遅くなります。


-2
DECLARE @PageIndex int;
DECLARE @PageSize int;
SET @PageIndex = 4;
SET @PageSize = 5;
;With ranked AS   --- Or you can make it a view
(
   SELECT ROW_NUMBER() OVER(ORDER BY IdentityId) AS RowNum,  *
   FROM logeventnew
)
SELECT *   --Your fields here
FROM Ranked
WHERE RowNum BETWEEN ((@PageIndex - 1) * @PageSize + 1)
    AND (@PageIndex * @PageSize)
ORDER BY IdentityId

4
答えを詳しく教えてください。質問は、ページングがSQL Serverの内部でどのように機能する、つまり、データベースエンジンが要求を満たすために何をするかに関するものでした。残念ながら、今のところ、あなたの答えは実際の懸念に対処していません。
Mr.Brownstone
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.