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

Fab*_*hri 6 performance entity-framework dottrace

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

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

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

这篇博文说明了这一点

实体框架将遍历表达式树中的节点并创建一个哈希,该哈希将成为用于将其置于查询缓存中的密钥.

因此,似乎哈希值仅用作查询缓存的键.由于我们在查询中使用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..
Run Code Online (Sandbox Code Playgroud)

我们希望不再调用ComputeHashValue().但是,dotTrace显示的调用树没有任何变化,性能与启用查询计划缓存的性能完全相同.

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

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

Rik*_*erg 0

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

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