I have a simple EF implementation in which I retrieve ~20K records and include two child entities:
using (InsightEntities context = new InsightEntities()) { return context.Accounts .Include(x => x.Division) .Include(x => x.Division.Company) .OrderBy(x => x.ID) .AsNoTracking() .ToList(); }
When I profile the EF call via SQL Profiler, the duration of the SQL command is ~1.2s, even on subsequent calls. But if I copy and paste the same SQL that EF is generating and run it directly through SSMS, the duration is half that.
Below is a screenshot of EF calls (red ovals) and direct calls (green ovals):
I understand that EF does a lot of work mapping data to objects, interpreting relationships, and so on, but why would the query alone take twice as long as the same query run directly? Are there changes to the default EF connection string that might optimize the queries?
(I should add that the query itself is completely optimized with indices for all foreign keys.)
Thank you!
The reads are the same between the two traces so it doesn't look plan related.
Quite likely it is just because Entity Framework does more when it consumes the result set so takes longer.
For example creating the following scalar UDF
CREATE FUNCTION dbo.GetTime() RETURNS CHAR(12) AS BEGIN RETURN CONVERT(VARCHAR(12), GETDATE(), 114) END
Then running in Management Studio
SELECT TOP (10) CAST(dbo.GetTime() AS CHAR(8000)) FROM sys.all_objects
Completes almost instantly but simulating a client that does more work
using (SqlConnection con = new SqlConnection(connectionString)) { con.Open(); using (SqlCommand command = new SqlCommand( @"SELECT TOP (10) CAST(dbo.GetTime() AS CHAR(8000)) FROM sys.all_objects", con)) { using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { Console.WriteLine(reader.GetString(0).TrimEnd()); System.Threading.Thread.Sleep(1000); } } } }
Shows up in Profiler as duration 8 seconds.
The results of the run shown above are
23:55:54:870 23:55:54:870 23:55:54:870 23:55:55:870 23:55:56:870 23:55:57:870 23:55:58:870 23:55:59:870 23:56:00:870 23:56:01:870
The difference in time stamps between 1st and last row are 7 seconds. The first three rows were returned almost immediately and there after SQL Server was delayed waiting on the client (with wait type ASYNC_NETWORK_IO
) before continuing with execution.
The Include statements are known to cause slowdowns. I am not exactly sure why. Try commenting-out your include statements and use lazy loading instead. Here is another SO article with the same conclusion: Why is Entity Framework taking 30 seconds to load records when the generated query only takes 1/2 of a second?