ObjectQuery MergeOptionを「NoTracking」に宣言するクエリを実行しようとする奇妙な動作があります。この場合、エンティティフレームワークはエンティティをアタッチせず、エンティティの状態を追跡するための相対ObjectStateEntryを作成するべきではありません。
問題は、パフォーマンスを向上させるのではなく、同じクエリがデフォルトのmergeoption(つまりAppendingOnly)で10秒のようにかかり、notrackingを指定しようとすると1分かかることです。
誰かがこれについて説明がありますか?
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の管理と多重化されたオブジェクトの具体化の欠点により、無効にされた変更の追跡が破壊されます。