121

ページングにLINQ のSkip()andTake()メソッドを使用するか、SQL クエリを使用して独自のページングを実装する必要がありますか?

どれが最も効率的ですか? なぜ私は他のものよりも1つを選ぶのでしょうか?

SQL Server 2008、ASP.NET MVC、および LINQ を使用しています。

4

10 に答える 10

52

使ってみて

FROM [TableX]
ORDER BY [FieldX]
OFFSET 500 ROWS
FETCH NEXT 100 ROWS ONLY

メモリにロードせずに、SQL サーバーで 501 から 600 までの行を取得します。この構文は、SQL Server 2012でのみ使用できるようになったことに注意してください。

于 2012-12-21T13:38:27.760 に答える
13

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とも呼ばれます。

于 2013-10-26T17:30:28.330 に答える
5

LinqToSql は自動的に .Skip(N1).Take(N2) を TSQL 構文に変換します。実際、Linq で実行するすべての「クエリ」は、実際にはバックグラウンドで SQL クエリを作成しているだけです。これをテストするには、アプリケーションの実行中に SQL プロファイラーを実行します。

スキップ/テイクの方法論は、私と私が読んだ他の人にとって非常にうまく機能しています。

好奇心から、Linq のスキップ/テイクよりも効率的だと思われる、どのタイプのセルフページング クエリがありますか?

于 2009-02-14T04:51:18.903 に答える
2

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 にはそのページに対応するレコードのみが含まれます

于 2014-03-20T00:55:55.383 に答える
0

パフォーマンスをさらに向上させることができます。これを確認してください

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 による回答は本当に役に立ちます。

ありがとう

于 2012-02-09T07:47:33.057 に答える
0

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();
于 2018-04-19T07:06:33.430 に答える