How to reduce Entity Framework 4 query compile tim

2020-02-26 00:50发布

Summary: We're having problems with EF4 query compilation times of 12+ seconds. Cached queries will only get us so far; are there any ways we can actually reduce the compilation time? Is there anything we might be doing wrong we can look for? Thanks!

We have an EF4 model which is exposed over the WCF services. For each of our entity types we expose a method to fetch and return the whole entity for display / edit including a number of referenced child objects.

For one particular entity we have to .Include() 31 tables / sub-tables to return all relevant data. Unfortunately this makes the EF query compilation prohibitively slow: it takes 12-15 seconds to compile and builds a 7,800-line, 300K query. This is the back-end of a web UI which will need to be snappier than that.

Is there anything we can do to improve this? We can CompiledQuery.Compile this - that doesn't do any work until first use and so helps the second and subsequent executions but our customer is nervous that the first usage shouldn't be slow either. Similarly if the IIS app pool hosting the web service gets recycled we'll lose the cached plan, although we can increase lifetimes to minimise this. Also I can't see a way to precompile this ahead of time and / or to serialise out the EF compiled query cache (short of reflection tricks). The CompiledQuery object only contains a GUID reference into the cache so it's the cache we really care about. (Writing this out it occurs to me I can kick off something in the background from app_startup to execute all queries to get them compiled - is that safe?)

However even if we do solve that problem, we build up our search queries dynamically with LINQ-to-Entities clauses based on which parameters we're searching on: I don't think the SQL generator does a good enough job that we can move all that logic into the SQL layer so I don't think we can pre-compile our search queries. This is less serious because the search data results use fewer tables and so it's only 3-4 seconds compile not 12-15 but the customer thinks that still won't really be acceptable to end-users.

So we really need to reduce the query compilation time somehow. Any ideas?

  • Profiling points to ELinqQueryState.GetExecutionPlan as the place to start and I have attempted to step into that but without the real .NET 4 source available I couldn't get very far, and the source generated by Reflector won't let me step into some functions or set breakpoints in them.
  • The project was upgraded from .NET 3.5 so I have tried regenerating the EDMX from scratch in EF4 in case there was something wrong with it but that didn't help.
  • I have tried the EFProf utility advertised here but it doesn't look like it would help with this. My large query crashes its data collector anyway.
  • I have run the generated query through SQL performance tuning and it already has 100% index usage. I can't see anything wrong with the database that would cause the query generator problems.
  • Is there something O(n^2) in the execution plan compiler - is breaking this down into blocks of separate data loads rather than all 32 tables at once likely to help? Setting EF to lazy-load didn't help.
  • I've bought the pre-release O'Reilly Julie Lerman EF4 book but I can't find anything in there to help beyond 'compile your queries'.

I don't understand why it's taking 12-15 seconds to generate a single select across 32 tables so I'm optimistic there's some scope for improvement!

Thanks for any suggestions! We're running against SQL Server 2008 in case that matters and XP / 7 / server 2008 R2 using RTM VS2010.

5条回答
做自己的国王
2楼-- · 2020-02-26 01:04

You could create a view for some of your more complex queries which gives you complete control of the SQL. Then include that view in your data model.

查看更多
Emotional °昔
3楼-- · 2020-02-26 01:06

Make your queries simpler. Seriously; there's an almost linear relationship between query complexity and compile time. Two simple queries are often much faster than one really complicated query (even if precompiled!). If speed is the end goal, choose the fastest option.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2020-02-26 01:09

Take a look at nqueries, it uses precompiled queries, that are generated during application startup.

Edit: Since the switch to EF5, NQueries does no longer support compiled queries as it switched to DbContext, if you still would like to take a look, take the 1.03 release source code, which is still ObjectContext based and supports compiled queries.

查看更多
家丑人穷心不美
5楼-- · 2020-02-26 01:12

You can try to use http://www.iis.net/download/ApplicationWarmup It is in beta now, but we regarding to use it too.

查看更多
Viruses.
6楼-- · 2020-02-26 01:15

This is likely not the answer you are looking for, but for a simple workaround why don't you run the CompiledQuery.Compile at the time the webapp gets initialized (do some dummy call to the webapp) instead of the first (customer) call.

查看更多
登录 后发表回答