我已经尝试在不同的网站上寻找答案,但似乎没有人真正有解决方案。
我从数据库中加载了相当多的行,包括两个0对多关系。
测试是在Visual Studio 2010中使用Entity Framework 4.0 Model和POCO生成器进行的(常规实体和POCO对象之间的时间差异不大)。我还使用了T4 Views模板来预编译视图。
数据库位于SQL Server 2008上。
我真正想知道的是为什么第一个查询比任何次要查询都要慢这么多。
我还想知道是否可以采取某些措施提高第一个查询的速度,使其达到可接受的限制。
这是一个很大的查询,我们可能会得到其他更大的查询,而且它们可能会有点慢,但用户等待30秒的时间太长了,尤其是当数据集可以更快地获取相同的数据时。
我做了一些计时测试,试图找出问题所在。我有点惊讶地发现,第一个查询看起来是SQL Server很慢。
计时如下:
.NET测试应用程序:
- 第一次查询:29.6秒 - 第二次查询:3.2秒
SQL Profiler:
- 第一次查询:27秒 - 第二次查询:3.2秒
SQL Server查询窗口:
- 第一次查询:8秒 - 第二次查询:4秒
应用程序中的计时是使用Stopwatch类测量的。只测量了查询,并使用.ToList()执行了查询。
SQL Server Profiler中的时间轴是针对应用程序执行的相同查询,显示应用程序仅使用了约2.6秒将数据填充到对象中。
最后27秒用于在SQL Server上执行查询。
查看第二个查询,两个应用程序和SQL Server的时间轴都相同,但这次执行查询要快得多。
我可以理解为什么应用程序不需要任何时间,因为没有需要转换为对象的新行,但为什么查询要快得多,我希望只需要几秒钟,因为执行计划,但不是24秒。
仅用于测试目的,我复制了Entity Framework生成的SQL,并使用单独的连接打开了一个新的查询窗口,并在其中执行了查询。
如您所见,第一个查询需要8秒,第二个查询需要4秒。
我希望有人能提出一些建议。
附:对于文本墙我深表歉意 :)
编辑19-10-2010:
昨天我进行了一项测试,似乎支持按顺序返回行。这意味着当从数据库返回一行时,它会立即材料化(如果在上下文中不存在),然后返回下一行等等。
这就是为什么数据库服务器上的查询似乎需要很长时间,因为SQL Server Profiler时间轴中包含了材料化时间。
我不认为这是从硬盘上读取数据的情况。 EF中的第一个查询每次都会变慢。
例如:
- 使用EF运行第一个查询,该SQL语句比任何辅助查询都慢
- 释放上下文/存储库
- 创建新的上下文
- 再次运行与以前相同的查询(此时第一个查询仍然很慢,SQL语句也是如此)
这就像EF发送了一些选项,使服务器变慢。
就查询编译而言,据我所知,查询在第一次使用时被编译,这意味着第一次查询执行的时间会更长。
二次查询会更快,但是二次查询的速度不是问题所在。
我还进行了一个测试,将编译的查询作为静态查询创建,以便为创建的所有上下文编译查询。
然后我创建了一个上下文,运行了查询,销毁了上下文,创建了一个新的上下文并再次运行相同的查询。
差别并不是很大,只有几秒钟,而我第一次运行查询仍然像没有预编译时那样需要很长时间。
就视图生成而言,我们已经使用T4模板实现了它。
答案是否真的是EF只适用于简单查询并返回相对较少量数据的情况吗?