現在、Entity Framework クエリのパフォーマンスを最適化しようとしています。特に、CPU 使用率を削減する方法を探しています。
dotTrace を使用して、さまざまなクエリを実行するときに最も CPU 時間がかかるものを分析しました。以下のスナップショットを参照してください。
このスナップショットはかなり単純なクエリからのものですが、最も時間のかかる操作である GetExecutionPlan() を示しています。これをさらに掘り下げると、式ツリー内のすべてのノードに対して再帰的に呼び出されるメソッド ComputeHashValue() に多くの時間が費やされていることがわかります。
このブログ投稿では、
Entity Framework は式ツリー内のノードをたどり、クエリ キャッシュに配置するために使用されるキーとなるハッシュを作成します。
そのため、ハッシュ値はクエリ キャッシュのキーとしてのみ使用されているようです。クエリで IEnumerable.Contains() を使用しているため、EF はそれらをキャッシュしません (この MSDN の記事 (3.2 章と 4.1 章) を参照してください)。したがって、次のようにクエリ プランのキャッシュを無効にしました。
var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var objectSet = objectContext.CreateObjectSet<Customer>();
objectSet.EnablePlanCaching = false;
// use objectSet for queries..
その後、ComputeHashValue() が呼び出されなくなることを願っていました。ただし、dotTrace によって表示されるコール ツリーに変化はなく、パフォーマンスはクエリ プラン キャッシュを有効にした場合と同じでした。
クエリ プランのキャッシュが無効になっているときに ComputeHashValue() がまだ必要な理由はありますか?
より複雑なクエリの場合、ComputeHashValue() へのすべての呼び出しは、クエリの実行に必要な CPU 時間全体の最大 70% を占めるため、これらの呼び出しを (必要がない場合) 回避すると、パフォーマンスに大きな影響を与えます。