LINQ2SQLでのEntitySetとテーブルクエリのパフォーマンス
-
03-07-2019 - |
質問
LINQ to SQLクラスでは、 IEnumerable
を実装する外部キー EntitySet
オブジェクトから作成されるプロパティが、なぜ > DataContext
は、 IQueryable
?
Table
オブジェクトです
編集:明確にするために、理解しようとしていることを示す例を示します。この例:
ctx.Matches.Where(x => x.MatchID == 1).Single()
.MatchPlayers.Max(x => x.Score);
次のように、データベースに2回ヒットします。
ctx.MatchPlayers.Where(x => x.MatchID == 1)
.Max(x => x.Score);
1つのクエリのみを実行します。トレースは次のとおりです。
exec sp_executesql N'SELECT [t0].[MatchID], [t0].[Date]
FROM [dbo].[Matches] AS [t0]
WHERE [t0].[MatchID] = @p0',N'@p0 int',@p0=1
go
exec sp_executesql N'SELECT [t0].[MatchID], [t0].[PlayerID], [t0].[Score]
FROM [dbo].[MatchPlayers] AS [t0]
WHERE [t0].[MatchID] = @p0',N'@p0 int',@p0=1
go
and
exec sp_executesql N'SELECT MAX([t0].[Score]) AS [value]
FROM [dbo].[MatchPlayers] AS [t0]
WHERE [t0].[MatchID] = @p0',N'@p0 int',@p0=1
go
これは、さらに悪いことに、最大値がデータベースではなくC#レベルで実行されることも示しています。
これが発生する理由は IQueryable
sと IEnumerable
sの違いであることがわかっているので、 MatchPlayers
オブジェクトが最初の例では、 IQueryable
インターフェースを実装して、後者の例と同じ利点を取得します。
解決
テーブルは事実上概念上の問題です。テーブルは実際にサーバー上に存在するため、エントリを取得するにはクエリを実行する必要があります。外部キーエントリは、別のクエリによって実際にフェッチされたものであるため、その時点でローカルに利用可能です。これはかなり馬鹿げた説明ですが、願わくは一般的な概念を乗り越えることを願っています。
他のヒント
ctx.Matches.Where(x => x.MatchID == 1).Single()
Single()は、IQueryable(Match)ではなくMatchを返します。
Single()を最後のステップにプッシュするだけです:
ctx.Matches
.Where(m => m.MatchID == 1)
.Select(m => m.MatchPlayers.Max(mp => mp.Score))
.Single();
このクエリが示すのは、クエリでMatchPlayersプロパティを使用してもかまわないということです。質問者の質問の私の解釈に対処するのは、「クエリでEntitySetを使用できないのはなぜですか?」ということです。
これは MSDNフォーラムで対処。推論の要点は、データベースに対してクエリを実行しながら、追加および削除されたオブジェクトを追跡することは非常に難しいということです。代わりに、EntitySetは、操作可能な関連オブジェクトのローカルコピーのようなものです。残念ながら、お気づきのとおり、これには、LINQ to SQLのパフォーマンスが向上する代わりに、式をLINQ to Objects呼び出しに変換するという副作用があります。