8

摘要:我们遇到了 EF4 查询编译时间超过 12 秒的问题。缓存查询只能让我们走这么远;有什么方法可以真正减少编译时间?有什么我们可能做错的事情我们可以寻找吗?谢谢!

我们有一个通过 WCF 服务公开的 EF4 模型。对于我们的每个实体类型,我们公开了一个方法来获取和返回整个实体以进行显示/编辑,包括许多引用的子对象。

对于一个特定实体,我们必须 .Include() 31 个表/子表来返回所有相关数据。不幸的是,这使得 EF 查询编译速度非常慢:编译和构建一个 7,800 行、300K 的查询需要 12-15 秒。这是 Web UI 的后端,需要比这更敏捷。

我们能做些什么来改善这一点吗?我们可以 CompiledQuery.Compile 这个 - 在第一次使用之前不会做任何工作,因此有助于第二次和随后的执行,但我们的客户担心第一次使用也不应该很慢。同样,如果托管 Web 服务的 IIS 应用程序池被回收,我们将丢失缓存计划,尽管我们可以增加生命周期以最小化这种情况。此外,我看不到提前预编译和/或序列化 EF 编译查询缓存(缺少反射技巧)的方法。CompiledQuery 对象仅包含对缓存的 GUID 引用,因此它是我们真正关心的缓存。(写出来这件事发生在我身上,我可以从 app_startup 在后台启动一些东西来执行所有查询以编译它们 - 这安全吗?)

但是,即使我们确实解决了这个问题,我们也会根据我们正在搜索的参数使用 LINQ-to-Entities 子句动态构建搜索查询:我认为 SQL 生成器做得不够好,我们可以移动所有这些逻辑都进入 SQL 层,所以我认为我们不能预编译我们的搜索查询。这不太严重,因为搜索数据结果使用较少的表,因此编译时间仅为 3-4 秒而不是 12-15 秒,但客户认为最终用户仍然无法接受。

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

  • Profiling 指向 ELinqQueryState.GetExecutionPlan 作为开始的地方,我试图介入,但没有真正的 .NET 4 源可用,我无法走得很远,Reflector 生成的源不会让我介入函数或在其中设置断点。
  • 该项目是从 .NET 3.5 升级的,因此我尝试在 EF4 中从头开始重新生成 EDMX,以防万一出现问题,但这并没有帮助。
  • 我已经尝试过这里宣传的 EFProf 实用程序,但它看起来并没有帮助。无论如何,我的大型查询会使它的数据收集器崩溃。
  • 我已经通过 SQL 性能调优运行了生成的查询,它已经有 100% 的索引使用率。我看不出数据库有什么问题会导致查询生成器出现问题。
  • 执行计划编译器中是否存在 O(n^2) 的内容 - 是否将其分解为单独的数据加载块,而不是一次可能有帮助的所有 32 个表?将 EF 设置为延迟加载没有帮助。
  • 我已经购买了 O'Reilly Julie Lerman EF4 的预发行书,但除了“编译您的查询”之外,我无法在其中找到任何帮助。

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

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

4

5 回答 5

8

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

于 2010-04-29T18:45:31.363 回答
4

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

于 2010-04-30T11:17:36.263 回答
1

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

于 2010-04-30T15:45:23.183 回答
1

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

于 2010-04-29T18:04:25.077 回答
1

看一下nqueries,它使用在应用程序启动期间生成的预编译查询。

编辑:自从切换到 EF5,NQueries 不再支持编译查询,因为它切换到 DbContext,如果您仍然想看一下,请查看1.03 版本源代码,它仍然基于 ObjectContext 并支持编译查询。

于 2011-04-12T07:52:49.707 回答