包含的实体框架性能问题

时间:2014-01-24 08:07:32

标签: c# entity-framework

我想知道哪个性能更好

 var allocations = 
        Catalog.ResourceAllocations
               .Where(c => c.Pet.Key == petKey && c.Pet.Owner.Key == ownerKey)
               .Include(k => k.Appointment)
               .Include(k => k.Service)
               .Include(k => k.Appointment.Provider.Address)
               .ToList();

var allocations = 
       Catalog.ResourceAllocations
              .Where(c => c.Pet.Key == petKey && c.Pet.Owner.Key == ownerKey)
              .Include(k => k.Appointment.Provider.Address)
              .Include(k => k.Service)
              .ToList();

1 个答案:

答案 0 :(得分:4)

DbQuery<T>.Include(path)州的文档(最后请阅读 NOTES - 介绍路径如何工作):

  

路径包罗万象。例如,如果包含呼叫指示   包含(“Orders.OrderLines”),不仅包括OrderLines,   还有订单。

所以k.Appointment.Provider.Address无论如何都会包含k.Appointment。即使没有性能损失,第二个查询也更好,因为它不包含重复的包含定义。

更新:数据库查询中没有性能差异,因为两个LINQ查询都会生成相同的SQL查询(嗯,LEFT OUTER JOINS的顺序可能不同)。但是在查询生成方面会有很小的性能差异,因为当你包含一些路径时,会生成新的ObjectQuery(是的,每个Include创建新的查询而不是修改现有的查询。)

注意:有趣的是,知道为什么没有区别 - 我对Entity Framework 6源进行了一些调查,并找到了EF如何收集应该包含的路径的方式。内部密封类Span包含路径集合,以确定查询中包含哪些元素。 SpanPath非常简单 - 它只是字符串列表的包装器,表示要包含的导航:

internal class SpanPath
{
    // you can think naviagations as path splitted by dots
    public readonly List<string> Navigations;
    // ...
}

Span是一个包含所有包含路径的类:

internal sealed class Span
{
    private readonly List<SpanPath> _spanList = new List<SpanPath>();

    public void Include(string path)
    {
        Check.NotEmpty(path, "path");
        SpanPath spanPath = new SpanPath(ParsePath(path));
        this.AddSpanPath(spanPath);
    }

    internal void AddSpanPath(SpanPath spanPath)
    {
        if (this.ValidateSpanPath(spanPath))
        {
            this.RemoveExistingSubPaths(spanPath);
            this._spanList.Add(spanPath);
        }
    }

    private bool ValidateSpanPath(SpanPath spanPath)
    {
        for (int i = 0; i < this._spanList.Count; i++) 
        {           
            if (spanPath.IsSubPath(this._spanList[i]))                
               return false;    
        }

        return true;
    }
}

所以,这就是发生的事情 - 当你包含新路径时,那么:

  1. 将其拆分为字符串列表并包装到SpanPath
  2. 如果当前路径是某些已添加路径的子路径,那么我们只是忽略它
  3. 否则我们检查导航中是否存在当前路径的子路径。如果是,我们删除所有子路径
  4. 现在我们可以添加新路径。
  5. 如果您在第一种情况下包含Appointment.Provider.Address路径,则会在步骤3中删除Appointment路径,因为它是Appointment.Provider.Address的子路径。

    摘要

    不要在查询中明确包含子路径 - 它将导致新的ObjectQuery实例创建,并且它不会影响生成的查询。它将被忽略,或者在您添加包含此路径的路径时将被删除。