2

SQL Express 2008 R2 サーバーから EntityFramework 4 経由で WCF サービスを介して比較的多数のレコードを WCF クライアントに返したいと考えています。私のテスト テーブルには、現時点で約 11.000 のレコードが含まれています。LINQ クエリは次のように単純です。

Database DB = new Database(); // create object context
var retValue = DB.Entities.Persons
        .Include("District")
        .Include("District.City")
        .Include("District.City.State")
        .Include("Nationality")

return retValue.ToList();

これには約 10 秒かかります。

同じ SELECT クエリを SQL Server Managament Studio で実行すると、1 秒もかかりません。

EF でそれほど遅くする必要がありますか?

4

2 に答える 2

5

クエリは単純ではありません。( Includes による) 多くの結合が含まれており、さらに重要なことに、特に含まれているナビゲーション プロパティがコレクションである場合、多くの重複データが返される可能性があります: https://stackoverflow.com/a/5522195 /270591

時間のかかる部分は、オブジェクトの実体化と、データベースからの結果が Entity Framework コンテキストに返されるときにエンティティをコンテキストにアタッチすることです。

これは、同じコンテキスト内の 2 番目のクエリが非常に高速であるという測定 (質問へのコメント) によって確認されます。この場合、EF はデータベースに対してクエリを実行しますが、オブジェクトはまだコンテキストにアタッチされているため、オブジェクトを再度具体化する必要はありません。

2 番目のコンテキストで 2 番目のクエリを実行する場合、結果のエンティティは新しいコンテキストにアタッチする必要があります。この手順も低速です (測定によっても確認されます)。

これはおそらく、EF を使用したクエリが実際には遅く、生の SQL クエリと比較して多くのオーバーヘッドが追加されるポイントです。EF は、変更の追跡と、追加の時間を消費するコンテキストでのオブジェクト ID の管理のために準備された多くのデータ構造を作成する必要があります。

パフォーマンスを改善する唯一の方法は、変更追跡を無効にすることです (おそらく、操作には必要ありません)。EF 4.0 では /ObjectContext次のようになります。

Database DB = new Database();
DB.Entities.Persons.MergeOption = MergeOption.NoTracking;
// MergeOption is in System.Data.Objects namespace

このアプローチを使用する場合、関連するオブジェクトが同じキーを持っている場合でも別のオブジェクトとして作成されることに注意する必要があります。これは、コンテキストにアタッチするとこの重複が回避されるため、変更追跡が有効になっている場合には当てはまりません。

そのため、より多くのオブジェクトがメモリに読み込まれる可能性があります。これが逆効果であり、実際にパフォーマンスがさらに低下するか、またはそれでもパフォーマンスが向上するかは、テストの問題です。

于 2012-04-04T13:28:35.510 に答える
0

これは、クエリのコンパイル (多くのインクルードを含む LINQ クエリ -> 使用する SQL) がクエリの実行に比べて EF で非常に遅いためです。これが問題かどうかは、CPU がコードをプロファイリングすることで確認できます。コンパイル済みのクエリを使用するか、最新の EF5 ベータ版にアップグレードすることで、より少ないインクルードと複数の小さなクエリを使用することを検討してください。

于 2012-04-05T09:15:14.550 に答える