1. ホーム
  2. sql

[解決済み] ページングの効率的な実装方法

2022-09-13 18:37:48

質問

LINQの Skip()Take() メソッドでページングを行うか、SQLクエリで独自のページングを実装しますか?

どちらが最も効率的ですか?なぜどちらかを選ぶのでしょうか?

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

どのように解決するのですか?

あなたの疑問に対する簡単な答えを出そうとすると、もしあなたが skip(n).take(m) メソッドを linq で実行した場合 (SQL 2005 / 2008 をデータベースサーバーとした場合)、クエリは Select ROW_NUMBER() Over ... ステートメントを使用し、SQL エンジンで何らかの形で直接ページングされます。

例を挙げると、私は以下のようなDBテーブルを持っています。 mtcity という名前のテーブルがあり、次のようなクエリを書きました(linq to entitiesでも同様に動作します)。

using (DataClasses1DataContext c = new DataClasses1DataContext())
{
    var query = (from MtCity2 c1 in c.MtCity2s
                select c1).Skip(3).Take(3);
    //Doing something with the query.
}

結果のクエリーは

SELECT [t1].[CodCity], 
    [t1].[CodCountry], 
    [t1].[CodRegion], 
    [t1].[Name],  
    [t1].[Code]
FROM (
    SELECT ROW_NUMBER() OVER (
        ORDER BY [t0].[CodCity], 
        [t0].[CodCountry], 
        [t0].[CodRegion], 
        [t0].[Name],
        [t0].[Code]) AS [ROW_NUMBER], 
        [t0].[CodCity], 
        [t0].[CodCountry], 
        [t0].[CodRegion], 
        [t0].[Name],
        [t0].[Code]
    FROM [dbo].[MtCity] AS [t0]
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]

これはウィンドウデータアクセスです(非常にクールな、btw cuzは非常に最初からデータを返し、条件が満たされている限り、テーブルにアクセスします)。これは非常に似ています。

With CityEntities As 
(
    Select ROW_NUMBER() Over (Order By CodCity) As Row,
        CodCity //here is only accessed by the Index as CodCity is the primary
    From dbo.mtcity
)
Select [t0].[CodCity], 
        [t0].[CodCountry], 
        [t0].[CodRegion], 
        [t0].[Name],
        [t0].[Code]
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

例外として、この2番目のクエリはデータアクセスウィンドウを作成するためにインデックスのみを使用するため、linqの結果よりも速く実行されます。これは、何らかのフィルタリングが必要な場合、フィルタリングはエンティティリスト(行の作成場所)にあるべき(またはなければならない)で、良い性能を維持するためにはいくつかのインデックスも作成しなければならないことを意味しています。

さて、何が良いのでしょうか?

ロジックにかなりしっかりしたワークフローがある場合、適切なSQLの方法を実装するのは複雑になります。その場合、LINQが解決策になります。

ロジックのその部分を直接SQLに落とすことができれば(ストアドプロシージャで)、私が示した2番目のクエリを実装でき(インデックスを使用)、SQLがクエリの実行計画を生成して保存できるため(パフォーマンスを改善)、さらに良くなるでしょう。