web-dev-qa-db-ja.com

Entity Frameworkマージオプションがパフォーマンスを追跡しない

ObjectQuery MergeOptionを「NoTracking」に宣言するクエリを実行しようとする奇妙な動作があります。この場合、エンティティフレームワークはエンティティをアタッチせず、エンティティの状態を追跡するための相対ObjectStateEntryを作成するべきではありません。

問題は、パフォーマンスを向上させるのではなく、同じクエリがデフォルトのmergeoption(つまりAppendingOnly)で10秒のようにかかり、notrackingを指定しようとすると1分かかることです。

誰かがこれについて説明がありますか?

49
MaRuf

NoTrackingマージオプションを設定して変更の追跡を無効にすると、オブジェクトをコンテキストにアタッチするパフォーマンスコストを節約できますが、一方でID管理も失われます。

これは、潜在的にはるかに多くのオブジェクト(同じキーを持つオブジェクト)が具体化されることを意味します。

例:ナビゲーションプロパティとしてUserコレクションを持つRolesエンティティがあるとします。また、データベースに100万人のユーザーがいて、すべてのユーザーが同じ10個のロールを持っているとします。つまり、すべてのユーザーが10個の要素を持つロールコレクションを持っているとします。次のクエリを実行すると...

var users = context.Users.Include("Roles").ToList();

...マテリアライズおよびインスタンス化されたオブジェクトの数は、マージオプションによって異なります。

  • NoTrackingを使用しない場合、メモリ内に1.000.010のオブジェクト、つまり100万人のユーザーが存在しますが、IDマッピングによりキーごとに1つのロールのみが具体化され、コンテキストにアタッチされるため、10のロールしかありません。すべてのユーザーのRolesコレクションに同じ10個のロールインスタンスが使用されます。

  • ただし、NoTrackingを使用すると、EFはオブジェクトをコンテキストにアタッチしないため、ID管理が無効になり、メモリに11.000.000のオブジェクトが含まれます。ユーザーあたり100万のユーザーと10のロールインスタンス、つまり1000万役割オブジェクト。したがって、オブジェクトがコンテキストにアタッチされている場合の10倍以上のマテリアライズドオブジェクトがあります。

オブジェクトの具体化は "中程度の"パフォーマンスコスト で分類されます。

操作:オブジェクトの具体化
相対コスト:中程度
頻度:クエリが返すオブジェクトごとに1回。

コメント:返されたDbDataReaderオブジェクトを読み取り、オブジェクトを作成し、各インスタンスの値に基づくプロパティ値を設定するプロセスDbDataRecordクラス。 オブジェクトがObjectContextに既に存在し、クエリがAppendOnlyまたはPreserveChangesマージを使用する場合オプション、この段階はパフォーマンスに影響しません。

言い換えると、クエリがNoTrackingマージオプションを使用している場合、このステージはパフォーマンスに影響し、パフォーマンスが向上する可能性があります。無効にされたIDの管理と多重化されたオブジェクトの具体化の欠点により、無効にされた変更の追跡が破壊されます。

146
Slauma