EF efficiency: ComputeHashValue () in query compilation

We are currently trying to optimize the performance of our Entity Framework queries. In particular, we are looking for ways to reduce CPU usage.

Using dotTrace, we analyzed how much CPU time it takes to execute different requests. See the snapshot below: dotTrace Call Tree

This snapshot was taken from a fairly simple query, but it still shows which one is the most time-consuming: GetExecutionPlan (). Moreover, you can see that a lot of time is used in the ComputeHashValue () method, which is recursively called for all nodes in the expression tree.

This blog post states that

The Entity Framework will go through the nodes in the expression tree and create a hash that becomes the key used to place it in the cache request.

So, it seems that the hash values ​​are only used as a key for the query cache. Since we use IEnumerable.Contains () in our queries, EF will not read them (see this MSDN article (chapters 3.2 and 4.1) ., We disabled Query Plan Caching as follows:

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

We hoped that then ComputeHashValue () would no longer be called. However, there were no changes in the dotTrace metric in the Call Tree, and the performance was the same as when Query Plan caching was enabled.

Is there a reason ComputeHashValue () is still required when Query Plan caching is disabled?

For our more complex requests, all calls to ComputeHashValue () take up to 70% of the total processor time required to execute the request, so avoiding these calls (if they are not needed) will significantly affect our performance.

+6
source share
1 answer

Unfortunately, this is not how the Entity Framework was implemented. I looked at the source code a bit and I understand that it compiles ExecutionPlan anyway, it also calculates its HashValue. This is because if EnablePlanCaching enabled and it cannot find the cached request, it can then add it to the cache manager based on this ComputedValue.

Here is a link to a class that processes this logic: EntitySqlQueryState

0
source

All Articles