Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
390 views
in Technique[技术] by (71.8m points)

.net - Entity Framework - First query slow

As the title suggest I'm having a problem with the first query against a SQL Server database using Entity Framework.

I have tried looking for an answer on different sites but no one seems to actually have a solution to this.

I'm loading quite a lot of rows from the database including two 0-many relationships.

The tests was done in Visual Studio 2010 using the Entity Framework 4.0 Model and the POCO generator (there isn't much difference in timings between normal entities and POCO objects). I also used the T4 Views Template to pre-compile the views.

The database was on SQL Server 2008.

What I would really like to know is why the first query is soo much slower than any secondary queries.

I also want to know if something can be done to increase the speed of the first query to a point where it is within acceptable limits.

This is a big query and we may get other queries that are even bigger and it is understandable that they may be a bit slow but 30 seconds is way too slow for user to wait for especially when datasets can get the same data a lot faster.

I have done some timing tests to try and find out where the problem lies and i was a bit surprised to see that it looks like it is the SQL Server that is slow on the first query.

Timings was as follows:

.NET testing application:

  • First Query: 29,6 seconds
  • Second Query: 3,2 seconds

SQL Profiler:

  • First Query: 27 seconds
  • Second Query: 3,2 seconds

SQL Server Query Window

  • First Query: 8 seconds
  • Second Query: 4 seconds

Timings in the application was measured with the Stopwatch class. Only the query was measured and .ToList() was used to execute the query.

Timings in SQL Server Profiler is for the same queries that was executed in the application which shows that the application only use about 2,6 seconds to fill data into the objects.

The last 27 seconds is used for executing the query on SQL Server.

Looking at the secondary query the timings are the same for both application and SQL server but executing the query is much faster this time.

I can understand why the application doesn't use any time because there is no new rows that need to be converted to objects but why is the query so much faster, I would have expected a few seconds because of execution plans but not 24 seconds.

Just for testing purpose I copied the SQL that the Entity Framework generates and opened a new query window with a separate connection and executed the query in it.

As you can see it takes 8 seconds for the first query and 4 seconds for the second.

I hope someone have some suggestions.

ps. I apologize for the wall of text :)

Edit 19-10-2010:
I did a test yesterday that seems to support that rows are being returned in a sequential manner. Meaning that when a row is returned from the database it is immediately materialized (if it does not already exist in the context) then the next row is returned and so on.

That is why it appears that the query is taking a lot of time on the database server because materialization time is included in the SQL Server profiler timings.

I do not believe this to be a case of SQL Server reading from the harddisk. The slow query happens every time there is a "first query" in EF.

ex.

  1. Run the first query with EF, the SQL statement is slower then any secondary query
  2. Dispose the context/repository
  3. Create a new context
  4. Run the same query as before (again the first query is slow and so is the SQL statement)

It is almost like EF sends some options along with the first query that makes the server slow.

As for query compilation, as I remember the query is compiled the very first time it is used which means that the first query would take even longer to execute.

Secondary queries would be faster but the speed on secondary queries is not the issue.

I also did a test where i created a compiled query as a static so that it would be compiled for all contexts that was created.

I then created a context, ran the query, destroyed the context and created a new one and ran the same query once more.

The difference was not that big, only a few seconds and the very first time I ran the query it still took as long as without pre-compiling it.

As for view generation, we already implement this using T4 Templates.

Is the answer really that EF only works if you don't do anything but the simplest queries that return only a relatively small amount of data?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

We had the same issue in EF 5.0 and as of today a superficial Google search does not reveal a sufficient speed-up.

According to this link http://msdn.microsoft.com/en-us/library/cc853327(v=vs.100).aspx "Loading Metadata" carries a moderate time cost but only needs to occur once per AppDomain. I have found no pre-compilation like tricks for loading the meta-data.

The workaround we've implemented is to do a minor query on the Context in a separate thread when the application launches. This loads the meta-data, it still takes a long time (18-19 seconds in our case), but the app is responsive during the load. Also the first actual load does not take as long.

Please note that in our context it is possible for the user to spend 18-19 seconds in the application before an EF call will need to be made in response to their actions. Obviously if this is not possible in your application this work around may not provide much of a speed increase.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...