Why does a query generated by Entity Framework take twice as long to run as the same query run directly?

匿名 (未验证) 提交于 2019-12-03 01:23:02

问题:

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!

回答1:

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.



回答2:

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?



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!