简体   繁体   English

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

[英]EF Performance: ComputeHashValue() in query compilation

We are currently trying to optimize the performance of our Entity Framework queries. 我们目前正在尝试优化实体框架查询的性能。 In particular, we look for ways to reduce CPU usage. 特别是,我们寻找降低CPU使用率的方法。

Using dotTrace, we analyzed what costs the most CPU time when executing different queries. 使用dotTrace,我们分析了执行不同查询时CPU时间最多的成本。 See the snapshot below: 请参阅下面的快照: dotTrace调用树

This snapshot is from a rather simple query, but still it shows which is the most time consuming operation: GetExecutionPlan(). 此快照来自一个相当简单的查询,但它仍然显示哪个是最耗时的操作:GetExecutionPlan()。 Drilling into this even more, it can be seen that much time is used in the method ComputeHashValue() which is recursively called for all nodes in the expression tree. 进一步深入研究,可以看出,ComputeHashValue()方法使用了很多时间,该方法以递归方式为表达式树中的所有节点调用。

This blog post states that 这篇博文说明了这一点

The Entity Framework will walk the nodes in the expression tree and create a hash which becomes the key used to place it in the query cache. 实体框架将遍历表达式树中的节点并创建一个哈希,该哈希将成为用于将其置于查询缓存中的密钥。

So it seems that the hash values are only used as the key for the query cache. 因此,似乎哈希值仅用作查询缓存的键。 Since we are using IEnumerable.Contains() in our queries, EF will not chache them (see this MSDN article (chapters 3.2 & 4.1) . Therefore, we disabled Query Plan Caching like so: 由于我们在查询中使用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..

We hoped that then ComputeHashValue() would not be called anymore. 我们希望不再调用ComputeHashValue()。 However, there was no change in the Call Tree shown by dotTrace and performance was identical as with Query Plan Caching enabled. 但是,dotTrace显示的调用树没有任何变化,性能与启用查询计划缓存的情况相同。

Is there a reason why ComputeHashValue() is still needed when Query Plan Caching is disabled? 在禁用查询计划缓存时,是否还需要ComputeHashValue()?

For our more complex queries, all calls to ComputeHashValue() take up to 70% of the whole CPU time needed for the query execution, so avoiding these calls (if they are not needed) would impact our performance massively. 对于我们更复杂的查询,对ComputeHashValue()的所有调用占用查询执行所需的整个CPU时间的70%,因此避免这些调用(如果不需要)将大大影响我们的性能。

Unfortunately, that's not how Entity Framework was implemeted. 不幸的是,这不是实体框架的实施方式。 I've looked a bit at the source code and my understanding is because it is compiling an ExecutionPlan anyway, it also calculates it's HashValue. 我看了一下源代码,我的理解是因为它正在编译ExecutionPlan,它还计算它的HashValue。 This is because if EnablePlanCaching is enabled and it could not find a cached query, It can then add it to the cache manager based on this ComputedValue. 这是因为如果启用了EnablePlanCaching并且找不到缓存查询,则可以根据此ComputedValue将其添加到缓存管理器。

Here is a link to the class that handles this logic: EntitySqlQueryState 以下是处理此逻辑的类的链接: EntitySqlQueryState

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM