【问题标题】:Entity Framework 4.1 query takes too long (5 seconds) to completeEntity Framework 4.1 查询需要很长时间(5 秒)才能完成
【发布时间】:2012-01-02 17:21:37
【问题描述】:

我有 DbContext(称为“MyContext”),其中包含大约 100 个 DbSet。

在域类中,我有一个包含 10 个直接子类(如 PurchaseOrder、RequestForQuotation 等)的 Document 类。 层次结构使用 TPT 策略进行映射。 也就是说,在我的数据库中,有一个 Document 表,还有其他表,如 PurchaseOrder、RequestForQuotation 等子类。

当我进行如下查询时:

Document document = myContext.Documents.First();

查询用了 5 秒,无论是我第一次运行还是随后运行。

这样的查询:

Document document = myContext.Documents.Where(o => o.ID == 2);

也花了很长时间。

这是 EF4.1 的问题(如果是,EF4.2 会提供帮助)还是查询代码的问题?

【问题讨论】:

    标签: entity-framework entity-framework-4 entity-framework-4.1


    【解决方案1】:

    您是否尝试使用 SQL Profile 查看实际发送到数据库的内容?可能是您的 Document 上有太多未设置为延迟加载的联接,因此查询必须一次性完成所有联接,从而带回太多列。尝试发送一个只有一个返回列的简单查询。

    【讨论】:

      【解决方案2】:

      如您所见here,EF 中的 TPT 存在一些性能问题。

      EF 团队在 June 2011 CTP 中宣布了多项修复,包括 TPT 查询优化,但它们不包含在 EF 4.2 中,您可以在 cmets 中阅读 this answer

      在最坏的情况下,这些修复将仅在 .NET 4.5 中发布。我希望它会更快......

      【讨论】:

      • 我认为TPT继承很可能是问题的根源。 10张表的SQL查询会很糟糕。
      • TPT 继承可能非常有用,但我也遇到了关于它的性能问题。我使用了 5-6 张桌子。如果有 10 张桌子,我想情况会更糟。这就是我等待这些优化包含在 EF 中的原因之一。
      • 假设 TPT 是原因,您还使用哪些其他替代方法来解决它?
      • 根据您的域,您可以尝试移至其他继承映射选项,例如 Table-per-concrete-Class 或 Table-per-Hierarchy:blogs.msdn.com/b/adonet/archive/2010/10/25/…
      • 另一种选择是为您需要的查询创建存储过程,这样您就不需要更改数据库设计。
      【解决方案3】:

      我不确定代码优先公开的 DbSet 是否实际使用 ObjectQuery,但您可以尝试对其调用 .ToTraceString() 方法以查看生成了什么 SQL,如下所示:

      var query = myContext.Documents.Where(o => o.ID == 2);
      Debug.WriteLine(query.ToTraceString());
      

      获得 SQL 后,您可以确定是查询还是 EF 导致了延迟。根据基类的复杂性,查询可能包含许多额外的列,这可以使用投影来避免。使用投影,您可以执行如下查询:

      var query = from d in myContext.Documents
                  where d.ID == 2
                  select new
                  {
                      o.Id
                  };
      

      这应该基本上执行SELECT ID FROM Documents WHERE ID = 2 查询,您可以测量获得更多信息所需的时间。当然,预计的查询可能不符合您的需求,但它可能会让您走上正轨。如果这仍然需要长达 5 秒的时间,您应该查看数据库本身而不是 EF 的性能问题。

      更新 显然,在代码优先的情况下,您可以使用 .ToString() 而不是 .ToTraceString(),感谢 Slauma 的注意。

      【讨论】:

      • query.ToString() 而不是ToTraceString() 显示使用DbContext 时的SQL。
      【解决方案4】:

      我刚刚在从 SQL Management Studio 调用时立即运行的存储过程中的 ExecuteFunction 延迟了 5 秒。我通过重写程序来修复它。

      似乎 EF(和 SSRS BTW)试图对存储的 proc 和一些(通常是复杂的)proc 做一些可能需要很长时间的“准备”。

      一个快速而肮脏的解决方案是复制您的 SP 参数,然后用内部变量替换:

      create proc ListOrders(@CountryID int = 3, @MaxOrderCount int = 20)
      as
      declare @CountryID1 int, @MaxOrderCount1 int
      set @CountryID1 = @CountryID
      set @MaxOrderCount1 = @MaxOrderCount
      
      select top (@MaxOrderCount1) *
      from Orders
      where CountryID = @CountryID1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-10-27
        • 1970-01-01
        • 1970-01-01
        • 2014-01-15
        • 2018-02-07
        • 2016-07-30
        • 2013-07-18
        相关资源
        最近更新 更多