为什么实体框架生成的查询运行时间是同一查询直接运行的两倍?

时间:2013-08-21 17:33:15

标签: sql sql-server entity-framework entity

我有一个简单的EF实现,我在其中检索~20K记录并包含两个子实体:

using (InsightEntities context = new InsightEntities())
{
   return context.Accounts
   .Include(x => x.Division)
   .Include(x => x.Division.Company)
   .OrderBy(x => x.ID)
   .AsNoTracking()
   .ToList();
}

当我通过SQL事件探查器分析EF调用时,SQL命令的持续时间约为1.2秒,即使在后续调用中也是如此。但是,如果我复制并粘贴EF生成的相同SQL并直接通过SSMS运行它,则持续时间只有一半。

以下是EF电话(红色椭圆形)和直接电话(绿色椭圆形)的屏幕截图:

enter image description here

据我所知,EF在将数据映射到对象,解释关系等方面做了很多工作,但为什么单独的查询需要的时间是同一查询直接运行的两倍?是否有可能优化查询的默认EF连接字符串的更改?

(我应该补充说,查询本身已完全使用所有外键的索引进行优化。)

谢谢!

2 个答案:

答案 0 :(得分:3)

两条迹线之间的读取是相同的,因此它看起来与计划无关。

很可能只是因为Entity Framework在使用结果集时执行的操作更多,因此需要更长的时间。

例如,创建以下标量UDF

CREATE FUNCTION dbo.GetTime()
RETURNS CHAR(12)
AS
  BEGIN
      RETURN CONVERT(VARCHAR(12), GETDATE(), 114)
  END 

然后在Management Studio中运行

SELECT TOP (10) CAST(dbo.GetTime() AS CHAR(8000))
FROM   sys.all_objects 

几乎立即完成但模拟了做更多工作的客户

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);
            }
        }
    }
}

在Profiler中显示持续时间为8秒。

Profiler

上面显示的运行结果是

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

第1行和最后一行之间的时间戳差异为7秒。在继续执行之前,SQL Server在客户端上等待(等待类型为ASYNC_NETWORK_IO)后,几乎立即返回前三行。

答案 1 :(得分:1)

已知Include语句会导致速度减慢。我不确定为什么。尝试注释掉include语句并使用延迟加载。这是另一篇SO文章,结论相同: Why is Entity Framework taking 30 seconds to load records when the generated query only takes 1/2 of a second?