Entity Framework 和 SQL Server Profiler

3

我发现使用Web应用程序执行的EF查询和直接在SQL查询窗口中运行Profiler生成的T-SQL之间存在一些性能测量问题。

以下是通过Web应用程序执行的我的EF查询:

IEnumerable<application> _entityList = context.applications
                    .Include(context.indb_generalInfo.EntitySet.Name)
                    .Include(context.setup_budget.EntitySet.Name)
                    .Include(context.setup_committee.EntitySet.Name)
                    .Include(context.setup_fund.EntitySet.Name)
                    .Include(context.setup_appStatus.EntitySet.Name)
                    .Include(context.appSancAdvices.EntitySet.Name)
                    .Where(e => e.indb_generalInfo != null);

                if (isIFL != null)
                    _entityList = _entityList.Where(e => e.app_isIFL == isIFL);

                int _entityCount = _entityList.Count(); // hits the database server at this line

在SQL Profiler中跟踪上述EF查询,结果显示需要约 221'095毫秒才能执行完。(应用程序表包含30,000+条记录,indb_generalInfo包含11,000+条记录,appSancAdvices包含30,000+条记录)。

然而,当我从Profiler中复制T-SQL并直接从查询窗口运行它时,仅需要 4'000毫秒

为什么会这样?


你有没有尝试过多次运行相同的查询?Entity Framework仍然需要生成该查询,但它将被缓存以供将来请求使用。此外,如果你正在执行Count()操作,则无需进行急切加载。 - Simon Belanger
是的,我之前尝试过。但问题正是@Arnold通知的那样。 - Khadim Ali
4个回答

6
这个查询中的问题在于前几个单词:IEnumerable<application>。如果你将其替换为var(即IQueryable),查询将被翻译成SQL,直到最后一个Count()。这样做可以大大缩短时间,因为传输的数据量几乎为零。
此外,正如bobek已经提到的那样,你不需要这些Include,因为你只需要计算context.applications的项数。
除此之外,使用Entity Framework等ORM工具总是会带来一定的开销。

EF实现的IQueryable使用延迟执行,因此,正如您所说,查询直到调用Count()才会被翻译成SQL。您还可以调用AsEnumerable()或ToList()来强制翻译,当您开始使用无法翻译为SQL的过滤器时,这非常有用。但据我所知,仅仅将变量声明从IEnumerable更改为IQueryable不会有任何区别。 - Colin
@Colin,没问题。使用IEnumerable<application>与在第一条语句后调用AsEnumerable具有相同的效果,因此在应用LINQ语句的其余部分之前,强制将记录抓取到内存中,即使查询的执行被推迟到Count - Gert Arnold
1
我在我的代码中进行了测试,通过将变量声明从var更改为IEnumerable <>并从一个查询中删除对AsEnumerable()的调用,测试一个会因传递给EF而失败的查询。我可以确认@Gert是正确的。我纠正了自己的错误,并今天学到了新东西。因此,在问题中说它“在此行触发数据库服务器”是不正确的,这应该可以从在SQL Profiler中查看的查询中明显地看出-结果将是一个结果集,而不是一个整数。 - Colin
1
等一下 - 数据库将在 Count 处被访问,但数据库查询将返回一个结果集,并且计数将在内存中完成,对吧? - Colin
@GertArnold 但是有一件事让我感到惊讶。如果延迟是来自 EF 方面,为什么在 SQL Server Profiler 中需要 221'095ms 的时间! :O - Khadim Ali
显示剩余5条评论

0

自从 EF5 版本以后,默认情况下应该已经缓存了。 - phil soady

0

使用 EF 肯定会在性能方面有一定的成本。但它也提供了使用 Storedprocs 处理复杂 TSQL 的灵活性。但我认为它应该是你的最后选择。


0

如果您对性能和EF感兴趣。 http://msdn.microsoft.com/en-us/data/hh949853.aspx

然而...

在SQL Profiler中查看EF查询,发现它需要大约221'095毫秒才能执行。

然后..

从Profiler中复制T-SQL并直接从查询窗口运行它

SQL的来源无关紧要。 Q1花费x毫秒。根据SQL分析器信息 完全相同的查询Q1'基于SQL分析器需要更少的时间。这意味着SQL的来源不是问题,它暗示涉及环境问题。

最明显的解释是,SQL服务器已缓冲许多数据页面,并且可以更好地服务于第二个相同的请求。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接