一尘不染

为什么由Entity Framework生成的查询花费的时间是直接运行同一查询的时间的两倍?

sql

我有一个简单的EF实现,其中检索了约2万条记录,并包括两个子实体:

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会做很多工作,将数据映射到对象,解释关系等,但是为什么单独查询会比直接运行同一查询花费两倍的时间呢?是否对默认EF连接字符串进行了更改以优化查询?

(我应该补充一点,查询本身完全针对所有外键的索引进行了优化。)

谢谢!


阅读 127

收藏
2021-05-23

共1个答案

一尘不染

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

很有可能只是因为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);
            }
        }
    }
}

在事件探查器中显示为持续时间8秒。

探查器

上面显示的运行结果是

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

第一行和最后一行之间的时间戳差为7秒。前三行几乎立即返回,并且在SQL Server被延迟在客户端(具有waittypeASYNC_NETWORK_IO)之前等待,然后继续执行。

2021-05-23