EF Performance:查询编译中的ComputeHashValue()

时间:2014-04-29 09:25:47

标签: performance entity-framework dottrace

我们目前正在尝试优化实体框架查询的性能。特别是,我们寻找降低CPU使用率的方法。

使用dotTrace,我们分析了执行不同查询时CPU时间最多的成本。请参阅下面的快照: dotTrace Call Tree

这个快照来自一个相当简单的查询,但它仍然显示哪个是最耗时的操作:GetExecutionPlan()。进一步深入研究,可以看出,ComputeHashValue()方法使用了很多时间,该方法以递归方式为表达式树中的所有节点调用。

This blog post表示

  

实体框架将遍历表达式树中的节点   创建一个哈希,它成为用于将其置于查询中的键   高速缓存中。

因此,似乎哈希值仅用作查询缓存的键。由于我们在查询中使用IEnumerable.Contains(),因此EF不会对它们进行处理(请参阅this MSDN article (chapters 3.2 & 4.1)。因此,我们禁用了查询计划缓存,如下所示:

var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var objectSet = objectContext.CreateObjectSet<Customer>();
objectSet.EnablePlanCaching = false;
// use objectSet for queries..

我们希望不再调用ComputeHashValue()。但是,dotTrace显示的Call Tree没有变化,性能与启用查询计划缓存的效果相同。

在禁用查询计划缓存时,是否还需要ComputeHashValue()?

对于我们更复杂的查询,对ComputeHashValue()的所有调用占用查询执行所需的整个CPU时间的70%,因此避免这些调用(如果不需要它们)将大大影响我们的性能。

1 个答案:

答案 0 :(得分:0)

不幸的是,这并不是实体框架的实施方式。我看了一下源代码,我的理解是因为它正在编译ExecutionPlan,它还会计算它的HashValue。 这是因为如果启用EnablePlanCaching并且找不到缓存查询,则可以根据此ComputedValue将其添加到缓存管理器。

以下是处理此逻辑的类的链接:  EntitySqlQueryState

相关问题