【问题标题】:WCF RIA Services query slowWCF RIA 服务查询慢
【发布时间】:2011-11-20 13:34:07
【问题描述】:

我有一个由实体框架支持的 WCF RIA 服务域服务。实体模型相当复杂。一般来说,大多数操作的性能都可以。

但是我的 Silverlight 客户端包含一个主/详细信息视图。主视图是实体列表。在实体之间单击以选择它们会触发服务器上的 IQueryable GetEntity() 方法,这平均需要 5 秒 - 这是不可接受的时间量。

我使用 Fiddler 查看网络上的呼叫,我可以看到我所有的时间都花在了服务器上:

ServerGotRequest:   15:59:44.545
ServerBeginResponse:15:59:48.836
ServerDoneResponse: 15:59:48.836
ClientBeginResponse:15:59:48.836
ClientDoneResponse: 15:59:48.836
Overall Elapsed:    00:00:04.2940000

返回的数据,正如它在网络上显示的那样,也非常小。在这个例子中,大约 6kb。

好的 - 所以我的问题是服务器端。对 EF 的查询相当简单,有一个警告:我们有大约 25 个 .Include 语句来引入相关实体。 .Includes 选择实体最多 4 层深度(例如 .Include("1.2.3.4"))。

所以我的下一个想法是数据库很慢。不是这样 - 我运行 SQL Profiler 并看到(诚然可怕的)SQL 平均在 0.15 秒内被执行。返回的数据还不错 - 3 行,大约 275 列。

所以:

  • 我的瓶颈在服务器上
  • 我通过直接 EF 查询选择多个相关实体
  • 生成的 SQL 很丑,但速度够快

那我为什么慢?我该如何调试?

如果我在 IQueryable GetEntity() 方法的末尾设置断点,似乎在退出该方法后,实际查询出现在 SQL Profiler 中之前最多需要 3 秒。什么鬼?

请注意,我已经预先生成了我的实体框架视图,并且我尝试使用编译查询来排除 EF 的“预热”时间。没有区别。

感谢您对此问题的任何帮助。提前致谢。

【问题讨论】:

  • 你有没有找到一个可接受的答案来解决这个问题?我看到每次调用 RIA 服务的开销约为 0.8 秒。如果服务仅返回 DTO 而不是访问数据库或执行任何其他可能很慢的操作,则发生事件。
  • @Josh 看到我自己接受的答案。您需要弄清楚延迟在哪里;分析 Fiddler 中的网络调用和 SQL Profiler 中的 DB 调用,看看您在客户端、线路或服务器上是否速度较慢。
  • 谢谢。通过在我的代码中随处插入 ASP.Net 服务器跟踪,我找到了开销的原因。它最终是由 Unity 库内部抛出的大量异常引起的。大多数人认为它是 Unity 中的一个错误,但其作者除外。

标签: silverlight entity-framework wcf-ria-services


【解决方案1】:

我理解那些告诉我批量处理我的数据,而不是加载整个实体等的响应;总的来说,我同意这种方法。然而,在这种情况下,我们选择了一个实体——因为它来自一个规范化的数据库,这涉及到跨多个表的连接。

在这个确切的示例中,EF 生成的可怕查询仍然在 0.2 秒内执行。如果我愿意手写查询,可能会再次占用 1/10。事实上,它绝对足够快。线上整个实体的大小

所以对我来说,要在多个请求中批处理这个单个实体,在这个例子中根本不起作用。显然,如果我直接使用 ADO.NET 和 Web 服务/WCF,我就不会遇到这个问题。无论如何,继续回答:

我已经说过编译 EF 查询没有帮助。但是,这似乎可能是因为 RIA 服务在我的原始查询之上应用了“Where EntityID = ID”条件,并将我编译的查询吹走。

如果我只是在我的域服务中执行此操作:

(from e in ctx.Entities
.Include("SubEntity")
.Include("SubEntity.SubEntity")
// and so on, X20...
where e.EntityID == id
select e).FirstOrDefault();

这行代码几乎花费了整个时间来执行,但是 SQL 非常快。访问 SQL Server 的速度很慢。所以这对我来说意味着 EF 需要很长时间才能生成查询。

为了解决这个问题,我做了一个预编译查询,直接通过 ID 选择我的实体,并将其具体化,而不是返回 IQueryable:

 private static Func<DataContext, Guid, Entity> getEntityByEntityID =
        CompiledQuery.Compile<DataContext, Guid, Entity>(
        (ctx, id) => (from e in ctx.Entities
                        .Include("SubEntity")
                        .Include("SubEntity.SubEntity")
                        // and so on, X20...
                      where e.EntityID == id
                      select e).FirstOrDefault());

然后我在我的域服务上公开一个新操作以使用已编译的查询:

public Entity GetEntityByEntityID(Guid entityID)
    {
        return getEntityByEntityID(this.ObjectContext, entityID);
    }

结果:第一次调用时它现在有点慢。对于后续调用,整个服务调用的操作现在平均约为 0.5 秒。

【讨论】:

    【解决方案2】:

    对于这样的事情,我认为您通常最好使用包含。只需一次调用即可在 Silverlight 中加载您的主要实体,然后根据需要加载其他包含的项目。

    即使您最终需要视图中的所有它们,您也可能通过将它们分成更小的块并在获取它们时更新视图来获得更好的性能。它肯定会比等待查询提供更好的用户体验。

    【讨论】:

    • 是的,这可能是解决方案。我只是希望我知道这里发生了什么,而不是“性能很差”。
    • Julie Lerman 就在服务器端广泛使用 Include 提出警告,这也是我学到的一课。我相信您知道 EF 发出的 SQL 将数据延伸到一个长数据行中。然后,客户端上的内部逻辑必须通过此运行并将数据行的部分映射回各种表/实体。就应如何将数据返回给客户端而言,这并不理想。 MARS(多个活动记录集)更适合此问题,并且已针对存储过程实施以在客户端/服务器时代克服此问题。
    • 不仅仅是“性能差”。这是“你没有做对”。 :) J/k 普通应用程序不会将所有数据请求批处理到一个调用中,所以仅仅因为你可以并不意味着你应该这样做。不要包括所有内容。仅在需要时加载内容。这就是所有 Web 开发人员的工作方式,而不仅仅是 Silverlight。
    【解决方案3】:

    您解释它的方式 - 它是图形问题的序列化/反序列化。此外,当在 Analyzer 中执行 SQL 时运行速度很快,而在 EF 中运行速度很慢时,我们遇到了奇怪的问题。尝试在表上重建 statistcis

    【讨论】:

    • 是的,感觉就像 RIA 服务中某处的反序列化问题或 EF 中的查询/对象物化问题。但我无法在该级别进行分析或调试。这绝对不是 SQL。在访问数据库之前,我所有的时间都花在了代码上。
    【解决方案4】:

    在 WCF RIA 服务中 - 您必须记住,它们是在发出回调之前首先加载的客户端模型。此客户端模型不是 EF,而只是 EF 在服务器端的外观的呈现。 WCF RIA 服务调用首先加载此模型,然后再向底层模型中的实体发出带有 REFERENCE 的回调。

    我鼓励您查看 Rx 框架以利用多个异步调用,然后在心理上“完成工作”返回 UI 客户端。使用 Rx,您可以调用多个异步方法并等待所有方法都完成,然后再返回 UI。每个调用都会以较小的位加载客户端模型,从而允许在返回之前并行完成工作。请记住,这是一种 SOA 架构,很容易(自言自语)退回到阻塞调用的设计中。

    (任务并行库 (TPL) 也是另一种方式,但正在进入 SL5。我不太熟悉 TPL 以及何时使用 RX 和/或 TPL 之间的细微差别。)

    我已经使用这种策略将数据从我返回的数据的层次树中拉下来——第一个工作是上层,然后是下层,等等。请记住,客户端上的导航属性只不过是linq 在后台查询,其中主键用于过滤外键。客户端模型(此时它不是 EF 模型,而是接近它的模型)也具有引用完整性约束,但这些仅适用于插入记录时,而不适用于 LOADING 记录。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-26
      • 1970-01-01
      相关资源
      最近更新 更多