【问题标题】:Entity Framework & Linq performance problem实体框架和 Linq 性能问题
【发布时间】:2014-09-11 02:27:50
【问题描述】:

在分页 Product 对象列表时,我遇到了 Entity Framework 和 Linq 的性能问题:

var data =_service.GetAll(); 
var page = data.Skip((index) * pageSize).Take(pageSize);
list.Add(page.AsEnumerable); // ** its slow right here

我的测试数据库中有 1958 个产品,但是当上面的代码运行时,我可以看到执行了 3916 个(即 1958 *2)个单独的查询(通过查看 sql profiler)。

Product 类看起来像:

public class Product 
{
    public virtual int Id {get;set;}
    public virtual string ProductCode {get;set;}
    //..etc other properties
    public virtual ICollection<WarehouseProduct> WarehouseProducts { // etc }
    public virtual ICollection<InvoiceLine> InvoiceLines { // etc }
    // etc other navigation properties
}

在 sql profiler 中我可以看到这个查询执行了 3916 次:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[ProductId] AS [ProductId], 
// etc
FROM [dbo].[WarehouseProducts] AS [Extent1]

我做错了什么? Product 对象有 12 个不同的导航属性,但只有 WarehouseProduct 被查询了 3916 次。请注意,该查询没有 WHERE 子句,但两个表之间存在外键关系(这就是它是导航属性的原因)

【问题讨论】:

  • 你确定它执行了两次,而且你不只是在看BeginExec/EndExec形式的重复行吗?
  • 谢谢,您是正确的 - 它在配置文件中显示 SQL:BatchStarting 和 SQL:BatchEnding,因此它是 1958 次查询。但这仍然不能解释为什么它对每个产品都执行一次,并且没有任何 where 子句。
  • 能把GetAll方法的代码贴出来吗?
  • 是的,真的很难判断黑盒子内的实际查询发生了什么。
  • service.GetAll() 调用repository.GetAll(),这只是return ObjectSet.AsQueryable();

标签: c# linq performance entity-framework


【解决方案1】:

您必须在获得产品后访问Product.WarehouseProducts,所以 如果你使用实体,你想使用Products.Include("WarehouseProduct").Include("InvoiceLine") 在您的 GetAll() 方法中,这将告诉实体在同一查询中检索数据。

相关实体默认是延迟加载的,所以如果你不使用Include()来指定你的结果中包含哪些相关实体,那么每次你在代码中访问相关实体时,都会触发另一个数据库查找。

【讨论】:

  • 您能否向非 EF 专家解释这有什么帮助?
  • 我已经编辑了问题以准确显示 sql 查询发生的位置(标记为“** 这里很慢”)。我根本没有访问过 Product.WarehouseProducts - 这就是我无法理解所有查询的原因。
【解决方案2】:

page.AsEnumerable 导致查询的序列被评估和具体化。前面的语句,假设仍然启用延迟加载并且您正在查询 SQL 数据源,正在设置将构成要执行的 SQL 语句的条件。

您没有发布 GetAll() 方法,因此这可能是您的附加记录的来源。

生成的 SQL 查询应该有一个 TOP 作为选择的一部分,并且它应该返回一个包含多条记录的结果集,因此您可能没有分析正确的查询。

【讨论】:

    猜你喜欢
    • 2011-11-16
    • 2011-12-14
    • 2016-03-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多