我有一个简单的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电话(红色椭圆形)和直接电话(绿色椭圆形)的屏幕截图:
据我所知,EF在将数据映射到对象,解释关系等方面做了很多工作,但为什么单独的查询需要的时间是同一查询直接运行的两倍?是否有可能优化查询的默认EF连接字符串的更改?
(我应该补充说,查询本身已完全使用所有外键的索引进行优化。)
谢谢!
答案 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秒。
上面显示的运行结果是
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?