2010-04-29 79 views
7

摘要:我们遇到了EF4查询编译时间超过12秒的问题。缓存查询只会让我们到目前为止;有什么办法可以减少编译时间吗?有什么我们可能做错了,我们可以寻找?谢谢!如何减少Entity Framework 4查询编译时间?

我们有一个暴露在WCF服务上的EF4模型。对于我们的每个实体类型,我们公开一个方法来获取并返回整个实体进行显示/编辑,包括一些引用的子对象。

对于一个特定实体,我们必须包含()31个表/子表以返回所有相关数据。不幸的是,这使得EF查询编译非常慢:编译和构建7,800行,300K查询需要12-15秒。这是网络用户界面的后端,需要比这更快捷。

有什么我们可以做的改善呢?我们可以CompiledQuery.Compile这个 - 在第一次使用之前不做任何工作,所以可以帮助第二次和随后的执行,但是我们的客户很紧张,第一次使用也不应该慢。同样,如果托管Web服务的IIS应用程序池得到回收,我们将失去缓存的计划,尽管我们可以延长生命周期以尽量减少这种情况。另外我也看不到预先编译这种方法和/或串行化EF编译查询缓存(缺少反射技巧)的方法。 CompiledQuery对象只包含一个GUID引用到缓存中,所以它就是我们真正关心的缓存。 (写出来,它发生在我身上,我可以从app_startup启动背景中的某些东西来执行所有查询以便编译它们 - 这是否安全?)

但是,即使我们确实解决了这个问题,我们也建立了我们的搜索根据我们正在搜索的参数,使用LINQ-to-Entities子句动态查询:我不认为SQL生成器做了足够好的工作,以至于我们可以将所有逻辑移入SQL层,所以我不认为我们可以预编译我们的搜索查询。这不太严重,因为搜索数据结果使用较少的表,因此仅编译12-15小时只需3-4秒,但客户认为终端用户仍然不能接受。

所以我们真的需要以某种方式减少查询编译时间。有任何想法吗?

  • 分析点到ELinqQueryState.GetExecutionPlan作为开始的地方,我试图踏进那个,但没有提供真正的.NET 4源我不能走得很远,并通过反射器产生的源荣获”让我进入一些功能或设置断点。
  • 该项目从.NET 3.5升级,所以我试图在EF4中从零开始重新生成EDMX,以防出现问题但没有帮助。
  • 我试过在这里做广告的EFProf实用程序,但它看起来并不像它对此有帮助。无论如何,我的大型查询会使其数据收集器崩溃。
  • 我已经通过SQL性能调整运行生成的查询,它已经有100%的索引使用率。我看不到任何会导致查询生成器问题的数据库错误。
  • 执行计划编译器中是否存在O(n^2) - 是否将此分解为单独的数据加载块,而不是一次可能帮助的所有32个表?将EF设置为延迟加载没有帮助。
  • 我已经购买了预发布的O'Reilly Julie Lerman EF4书,但是我找不到任何内容来帮助“编译你的查询”。

我不明白为什么需要12-15秒才能在32个表格中生成单个选择,所以我很乐观有一些改进的空间!

感谢您的任何建议!我们正在针对SQL Server 2008运行,以防使用RTM VS2010的XP/7/server 2008 R2。

+0

我们也有这个问题,这是一个主要问题。执行查询的时间最多为2-300毫秒,而等待ELinqQueryState.GetExecutionPlan()需要8-9秒。这是在将EF无法处理的大型热切加载查询(用于每个qry需要2-4分钟等待ELinqQueryState.GetExecutionPlan())分解为许多更简单的热切加载查询之后。我想我们所能做的就是等待EF5,这应该可以缓解由此造成的一些痛苦。 – Mahol25 2012-02-16 12:08:34

+0

我已发布在msdn.forums关于这个问题,希望得到一些指导,在这里http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/055c5b55-2d2a-4298- a28c-32737c57ad8d – Mahol25 2012-02-16 14:25:21

+0

@ Mahol25谢谢 - 我会看那个帖子。我很抱歉地说,在我离开项目之前,我们从来没有把我们的疑问降低到一秒以内,所以我没有任何具体的建议让你超越已有的东西。 – Rup 2012-02-16 17:55:47

回答

7

使您的查询更简单。认真;查询复杂性和编译时间之间几乎存在线性关系。两个简单的查询通常比一个非常复杂的查询快得多(即使预编译!)。如果速度是最终目标,请选择最快的选项。

+0

非常感谢,并且很抱歉会花时间回来。是的,这就是我们最终为阅读显示案例做的或多或少的事情:将对象加载分解为几个较小的块,并对每个块进行预编译查询,然后将检索到的数据重新组合到我们正在使用的POCO对象中数据传输。为了安全起见,我们坚持为更新读取案件单个大型查询,而不是尝试将EF数据拼接在一起以获取组合结果对象。 – Rup 2010-05-25 16:04:41

+1

Nit-pick:线性关系意味着分裂它不会带来任何好处,并且由于每个查询常数较高可能会伤害它。 – 2011-11-16 05:01:38

+1

@ MerlynMorgan-Graham,目标是选择一对(或更多)简单但等价的查询,而不是将并发症分成两半。 – 2011-11-16 13:43:10

1

这可能不是您正在寻找的答案,但是对于一个简单的解决方法,您为什么不在webapp初始化时(对webapp执行一些虚拟调用)而不是第一次运行CompiledQuery.Compile (客户)电话。

+0

谢谢。是的,值得一试的是我可以在后台执行此操作 - 我不想在每次重新启动应用程序池时编译所有查询几分钟,以锁定网站。但是,这无助于加速我们在即时构建的搜索查询,因此无法缓存,就我所见。 (CompiledQuery.Compile调用实际上只是将查询与缓存GUID相关联并立即返回 - 直到第一次执行编译实际发生时为止。因此,我必须在启动时对每个已编译查询进行虚拟提取来触发编译。) – Rup 2010-04-29 18:32:06

+0

我们在app init中将它作为后台线程实现,并且不幸的是,它似乎并不总能奏效;它在单线程的情况下工作得很好,EF4缓存代码中没有线程依赖关系,所以我有点不知所措,因为它并不总是工作。然而,这在某些情况下确实有帮助,所以我们坚持使用它。感谢您的建议! – Rup 2010-05-25 16:06:20

4

您可以为一些更复杂的查询创建视图,从而使您可以完全控制SQL。然后在数据模型中包含该视图。

+0

非常感谢,并且很抱歉为此需要花上很长时间。是的,我们最终创建了一些只读查询(搜索结果等)的视图,但我们坚持为一般对象抓取构建对象树。 – Rup 2010-05-25 15:59:12

1

您可以尝试使用http://www.iis.net/download/ApplicationWarmup 它现在处于测试阶段,但我们也正在使用它。

+0

感谢您的建议,并抱歉花了很长时间回来。 那些权力说不,至少不是,虽然它仍然是一个测试版,所以我们最终在后台线程中做了类似的事情 - 不幸的是取得了有限的成功: -/ – Rup 2010-05-25 16:01:18

1

看看nqueries,它使用在应用程序启动过程中生成的预编译查询。

编辑: 由于开关至EF5,NQueries确实不再支持编译查询,因为它切换到的DbContext,如果你还是想看看,走1.03 release source code,它仍然是ObjectContext的基础,支持编译查询。

+0

谢谢。我会看看,但我们已经生成了CompiledQueries并尽可能使用预编译视图 - 我看不到它在启动时还能做些什么。 – Rup 2011-04-12 08:49:03