繁体   English   中英

包含的实体框架性能问题

[英]Entity Framework Performance issue with Include

我想知道哪个表现更好

 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();

DbQuery<T>.Include(path)文档指出(请最后阅读注释 -它描述了包括路径的工作方式):

路径是包罗万象的。 例如,如果一个include调用指示Include(“ Orders.OrderLines”),则不仅将包括OrderLines,还将包括Orders。

因此, k.Appointment.Provider.Address仍将包括k.Appointment 即使不影响性能,第二个查询还是更好的,因为它不包含重复的包含定义。

更新:数据库查询不会有性能差异,因为两个LINQ查询都将导致生成相同的SQL查询(嗯,左外部连接的顺序可能会有所不同)。 但是查询生成的性能会有细微的差别,因为当包含一些路径时,将生成新的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. 现在我们可以添加新路径。

如果在第一种情况下包括Appointment.Provider.Address路径,则Appointment路径将在步骤3中删除,因为它是Appointment.Provider.Address子路径。

摘要

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM