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:
SQL Profiler:
SQL Server Query Window
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.
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?
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.
I had same issue. And i used a trick to resolved that issue. As the Entity framework takes a bit more time while being access first time and then it cache some of the result first time on it level(sql server too cache the result separately). So i accessed the Entity framework on My application start asynchronously. It worked for me. And my application became smoother.
In Global.asax page
protected void Application_Start()
{
Start(() =>
{
using (EF.DMEntities context = new EF.DMEntities())
{
context.DMUsers.FirstOrDefault();
}
});
}
private void Start(Action a)
{
a.BeginInvoke(null, null);
}
Well, lots of things can make a SQL Server query slower the first time it is run. Most of them do not take multiple seconds, however.
… Except for hard drive random accesses. The first time you run the query, SQL Server may have to read the database pages from hard disk storage. The next time you run the query those pages are likely in memory.
Regarding the Entity Framework, the first time you run a query it must be compiled into SQL. You can use the CompiledQuery
type to pre-compile Entity Framework queries in order to do this work ahead of time, before the end user has to wait for it.
On a very large model, view generation take some time, as well. You can move this to compile time, instead. See this article for more such tips.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With