3

LINQ を使用して DB2 データベースからレコードを照会する必要があります。DB スキーマから生成されたエンティティがあり、Skip と Take を使用して LINQ クエリを実行しようとしています。基になるテーブルには、25 列ほどの列があり、おそらく 100 万のレコードがあります。「Skip()」なしでクエリを実行すると、完了するまでに約 0.508 ミリ秒かかります。Skip() を含めると、30 秒近くかかります。大きな違い。

なぜこれが起こっているのか誰にも教えてもらえますか?

更新:これが私が使用している LINQ クエリです。

var x = 30;

var results = context.ASSET_T
.OrderBy(c => c.ASSET_ID)
.Skip(x)
.Take(x)
.ToList();

UPDATE: ASSET_ID という 1 つの列のみを返すように、クエリを更新してみました。その 1 つの列のみを返す場合、Skip() を使用したクエリは .256 ミリ秒しかかかりません。

var x = 30;

var results = context.ASSET_T
.OrderBy(c => c.ASSET_ID)
.Skip(x)
.Take(x)
.Select(c => c.ASSET_ID)
.ToList();

追加の列を含めると、クエリの実行時間がDRAMATICALLY増加します。

たとえば、次のクエリは実行に 10 秒かかります。

var x = 30;

var results = context.ASSET_T
.OrderBy(c => c.ASSET_ID)
.Skip(x)
.Take(x)
.Select(c => new {
                 ASSET_ID = c.ASSET_ID,
                 ASSET_TYP = c.ASSET_TYP
                 ASSET_DESC = c.ASSET_DESC
                 })
.ToList();

更新:クエリしようとしているテーブルの列に問題があることを発見しました (おそらくインデックス関連)。前述したように、ASSET_ID 列のみを返すクエリを実行すると、わずか .256 ミリ秒しかかかりません。ASSET_DESC のみを返すクエリまたは ASSET_TYPのみ返すクエリを実行しようとすると、クエリの実行時間が約 9 秒に跳ね上がります。

これは、それらの他の列が現在索引付けされていないことを示していますか?

更新:上記の LINQ クエリからの SQL 出力を追加しました。

SELECT 
Project1.C1 AS C1, 
Project1.ASSET_ID AS ASSET_ID, 
Project1.ASSET_TYP AS ASSET_TYP, 
Project1.ASSET_DESC AS ASSET_DESC
FROM ( SELECT Project1.ASSET_ID AS ASSET_ID, Project1.ASSET_TYP AS ASSET_TYP, Project1.ASSET_DESC AS ASSET_DESC, Project1.C1 AS C1, row_number() OVER (ORDER BY Project1.ASSET_ID ASC, Project1.ASSET_TYP ASC, Project1.ASSET_DESC ASC) AS row_number
  FROM ( SELECT 
    Extent1.ASSET_ID AS ASSET_ID, 
    Extent1.ASSET_TYP AS ASSET_TYP, 
    Extent1.ASSET_DESC AS ASSET_DESC, 
    CAST(1 AS int) AS C1
    FROM MYDB.ASSET_T AS Extent1
  )  AS Project1
)  AS Project1
WHERE Project1.row_number > 1
ORDER BY Project1.ASSET_ID ASC, Project1.ASSET_TYP ASC, Project1.ASSET_DESC ASC FETCH  FIRST 31 ROWS ONLY 
4

2 に答える 2

3

このクエリ用に生成された SQL を見たことがありますか?

私が知る限り、Skip() Take() は最終的に Row_Number() という関数を使用するステートメントを生成します。この関数は、以下に示す方法でレコード セット全体で実行されます - 必要な開始値と終了値の間の値を取得する前に、結果の最初に生成された列として行番号を挿入するため、通常、大規模なレコードでは非常に遅くなります。セット..

SELECT ...
FROM (
    SELECT ROW_NUMBER() OVER (ORDER BY [t0].[...]) AS [ROW_NUMBER], ... ,
    FROM [table] AS [t0]
    ) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]

インデックス付きの数値列を使用して、 >= start_value AND <= end-value を自分で読み取るように配置できる場合、これらの値をページング量だけ上に移動すると、インデックスが使用され、ミリ秒単位で結果が返されます。

数億のレコードを含む適切にインデックス化されたデータベースがあり、Skip().Take() は 25 レコードを取得するのに最大 30 分かかる場合があります。直接読み取りには約20〜40ミリ秒かかります。

これは、ページングを実現するためのコーディング方法を考える必要があり、実際には実装できない可能性があることを意味します。

于 2013-11-13T17:32:18.393 に答える