ページングにLINQ のSkip()
andTake()
メソッドを使用するか、SQL クエリを使用して独自のページングを実装する必要がありますか?
どれが最も効率的ですか? なぜ私は他のものよりも1つを選ぶのでしょうか?
SQL Server 2008、ASP.NET MVC、および LINQ を使用しています。
ページングにLINQ のSkip()
andTake()
メソッドを使用するか、SQL クエリを使用して独自のページングを実装する必要がありますか?
どれが最も効率的ですか? なぜ私は他のものよりも1つを選ぶのでしょうか?
SQL Server 2008、ASP.NET MVC、および LINQ を使用しています。
使ってみて
FROM [TableX]
ORDER BY [FieldX]
OFFSET 500 ROWS
FETCH NEXT 100 ROWS ONLY
メモリにロードせずに、SQL サーバーで 501 から 600 までの行を取得します。この構文は、SQL Server 2012でのみ使用できるようになったことに注意してください。
LINQ-to-SQL は句を生成しますが(他の人が言及OFFSET
したようにエミュレートされる可能性があります)、SQL でページングを実行するためのまったく異なる、はるかに高速な方法があります。これは、こちらのブログ投稿で説明されているように、「シーク メソッド」と呼ばれることがよくあります。ROW_NUMBER() OVER()
SELECT TOP 10 first_name, last_name, score
FROM players
WHERE (score < @previousScore)
OR (score = @previousScore AND player_id < @previousPlayerId)
ORDER BY score DESC, player_id DESC
@previousScore
との@previousPlayerId
値は、前のページの最後のレコードのそれぞれの値です。これにより、「次の」ページを取得できます。ORDER BY
方向がの場合はASC
、単に>
代わりに使用します。
上記の方法では、最初に前の 40 レコードをフェッチしないと、すぐにページ 4 にジャンプすることはできません。しかし、多くの場合、とにかくそこまでジャンプしたくありません。代わりに、インデックス作成に応じて、データを一定時間で取得できる可能性があるはるかに高速なクエリを取得します。さらに、基になるデータが変更されても (たとえば、ページ 1 で、ページ 4 で)、ページは「安定」したままです。
これは、たとえば、Web アプリケーションでより多くのデータを遅延ロードする場合にページングを実装するための最良の方法です。
「seek メソッド」はkeyset pagingとも呼ばれます。
LinqToSql は自動的に .Skip(N1).Take(N2) を TSQL 構文に変換します。実際、Linq で実行するすべての「クエリ」は、実際にはバックグラウンドで SQL クエリを作成しているだけです。これをテストするには、アプリケーションの実行中に SQL プロファイラーを実行します。
スキップ/テイクの方法論は、私と私が読んだ他の人にとって非常にうまく機能しています。
好奇心から、Linq のスキップ/テイクよりも効率的だと思われる、どのタイプのセルフページング クエリがありますか?
SQL Server 2008 の場合:
DECLARE @PAGE INTEGER = 2
DECLARE @TAKE INTEGER = 50
SELECT [t1].*
FROM (
SELECT ROW_NUMBER() OVER (ORDER BY [t0].[COLUMNORDER] DESC) AS [ROW_NUMBER], [t0].*
FROM [dbo].[TABLA] AS [t0]
WHERE ([t0].[COLUMNS_CONDITIONS] = 1)
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN ((@PAGE*@TAKE) - (@TAKE-1)) AND (@PAGE*@TAKE)
ORDER BY [t1].[ROW_NUMBER]
t0 にはすべてのレコードが含まれます t1 にはそのページに対応するレコードのみが含まれます
パフォーマンスをさらに向上させることができます。これを確認してください
From CityEntities c
Inner Join dbo.MtCity t0 on c.CodCity = t0.CodCity
Where c.Row Between @p0 + 1 AND @p0 + @p1
Order By c.Row Asc
このように from を使用すると、より良い結果が得られます。
From dbo.MtCity t0
Inner Join CityEntities c on c.CodCity = t0.CodCity
理由: CityEntities テーブルで where クラスを使用しているため、MtCity に参加する前に多くのレコードが削除されるため、100% 確実にパフォーマンスが何倍にも向上します...
とにかく、rodrigoelp による回答は本当に役に立ちます。
ありがとう
2008 年には Skip().Take() を使用できません
方法は次のとおりです。
var MinPageRank = (PageNumber - 1) * NumInPage + 1
var MaxPageRank = PageNumber * NumInPage
var visit = Visita.FromSql($"SELECT * FROM (SELECT [RANK] = ROW_NUMBER() OVER (ORDER BY Hora DESC),* FROM Visita WHERE ) A WHERE A.[RANK] BETWEEN {MinPageRank} AND {MaxPageRank}").ToList();