6

我们目前正在尝试优化 Entity Framework 查询的性能。特别是,我们寻找减少 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..

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

禁用查询计划缓存时仍然需要 ComputeHashValue() 是否有原因?

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

4

1 回答 1

0

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

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

于 2014-05-03T19:35:21.640 回答