100万レコードのEmployee
テーブルがあります。 Webアプリケーションでデータをページングするために次のSQLを使用しています。正常に動作しています。ただし、私が問題として見ているのは、派生テーブルtblEmployee
がEmployee
テーブルのすべてのレコードを選択する(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
テストの代替手段は次のとおりです。
;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 ...;
私はこれについてもここでより詳細にブログを書いています:
その背後にあるメカニズムはわからないかもしれませんが、クエリのパフォーマンスを次のように比較することで自分でテストできます。select* from Employee。
最近のバージョンのSQL Serverは最適化にかなり優れていますが、いくつかの要因に依存する場合があります。
ROW_NUMBER関数の実行方法は、Order By句によって制御されます。あなたの例では、ほとんどがEmpIDが主キーであると推測します。
where句が非常に複雑であり、コード化またはインデックス化が不十分である場合、データセット全体を返すだけの方がよい場合があります(まれであり、修正できます)。 BETWEENの使用には問題があります。
すべての行をアプリケーションに返してそれを理解させるほうがよいと考える前に、クエリの最適化に取り組む必要があります。見積もりを確認してください。クエリアナライザーに問い合わせます。いくつかの代替案をテストします。
私は質問がrow_number()に関することを知っていますが、SQL Server 2012の新機能を1つ追加したいと思います。SQLServer 2012では、新機能OFFSET Fetchが次に導入され、row_number()よりも非常に高速です。私はそれを使用しました、そしてあなたたちも同じ経験を満たしてくれることを願って良い結果を私に与えます。
http://blogfornet.com/2013/06/sql-server-2012-offset-use/ で1つの例を見つけました
これは便利です。新しい機能の実装にも役立つことを願っています...