实体框架6-查询性能

时间:2020-01-21 09:12:04

标签: c# entity-framework-6 dbcontext

我使用Entity Framework 6,并且当前有一个包含许多包含的查询,该查询将大约1200个实体加载到dbContext中。加载实体似乎很慢,因为查询需要将近一分钟。我有什么可以做的表现吗?我有4个此类查询需要2.5分钟的加载时间? 启用了LazyLoading,但出于性能原因,我预加载了实体。

var report = DbContext.REPORT.Single(r => r.ID == reportId);

//this query takes a bit less than 1 minute
DbContext.REPORT_ELEMENT
    .Include(re => re.LAYOUT)
    .Include(re => re.PAGEMASTER)
    .Include(re => re.REPORT_ELEMENTS)
    .Include(re => re.SUBTITLE_CONTENT)
    .Include(re => re.REPORT_ELEMENT_NOTE)
    .Include("SUBTITLE_CONTENT.CONTENT_ELEMENT.LANGUAGE")
    .Include("TITLE_CONTENT.CONTENT_ELEMENT.LANGUAGE")
    .Where(re => re.REPORT_ID == report.ID)
    .Load();

3 个答案:

答案 0 :(得分:1)

性能建议:

  • 防止跟踪。以只读模式查询。
  • 防止在一个查询中获取太多数据。尝试分页。
  • 防止包含。查询中有太多Include个查询,这会导致性能下降。

防止跟踪

考虑为此添加AsNoTracking可以提高查询性能。

参考:https://docs.microsoft.com/en-us/ef/core/querying/tracking#no-tracking-queries

仅获取您需要的数据

查询缓慢的主要原因是它输出了太多数据。考虑添加:Take(200)Skip()以仅获取您所需或当前页面所需的数据。使用寻呼机生成报告。这可能会有所帮助。

防止Include

Include生成SQL以选择多个表。这大大增加了复杂性。您只能选择所需的数据,而不能编写Include函数。

例如,如果您只想获得盒子中的最后一个球,请考虑这样写:

public class Box
{
    public int Id { get; set; }
    public IEnumerable<Ball> Balls { get; set; }
}

public class Ball
{
    public int Id { get; set; }

    public int BoxId { get; set; }
    public Box Box { get; set; }
}
var boxes = await Boxes
            // DO NOT Call Include(t => t.Balls) here!
            .Where(somecondition)
            .Select(t => new Box(){
              Id = t.Id,
              Balls = t.Balls.OrderByDescending(x => x.CreationTime)
                         .Take(1) // Only get what you need
            })               
            .ToListAsync()

此外,当我们使用“选择”时,我们可以删除.Include,因为它在这里没有任何作用。

答案 1 :(得分:0)

除了Anduin的建议之外,我还要添加建议,以将Includes()分成几个不同的查询。 EF将能够跟踪同一DBContext中的实体之间的引用。根据经验,在同一查询中不要使用三个以上的Includes()。此外,还要确保在数据库中每个生成的JOIN都有一个索引。

为此,您必须在导航属性中另外公开实体中的FK字段。

您的初始查询将变成这样:

    DbContext.LAYOUT
        .Where(re => re.LAYOUT_ID == report.LAYOUT_FK)
        .Load();
    DbContext.PAGEMASTER
        .Where(re => re.PAGEMASTERT_ID == report.PAGEMASTER_FK)
        .Load();

答案 2 :(得分:0)

免责声明:我是项目Entity Framework Plus

的所有者

查询IncludeOptimized功能允许同时过滤包含和优化查询性能。

通常可以提高性能(将查询拆分为较小的查询)

DbContext.REPORT_ELEMENT
    .IncludeOptimized(re => re.LAYOUT)
    .IncludeOptimized(re => re.PAGEMASTER)
    .IncludeOptimized(re => re.REPORT_ELEMENTS)
    .IncludeOptimized(re => re.SUBTITLE_CONTENT)
    .IncludeOptimized(re => re.REPORT_ELEMENT_NOTE)
    .IncludeOptimized(re => re.SUBTITLE_CONTENT.Select(sc => sc.CONTENT_ELEMENT))  // SelectMany?
    .IncludeOptimized(re => re.SUBTITLE_CONTENT.Select(sc => sc.CONTENT_ELEMENT).Select(ce => ce.LANGUAGE)) // SelectMany?
    .IncludeOptimized(re => re.TITLE_CONTENT)
    .IncludeOptimized(re => re.SUBTITLE_CONTENT.Select(sc => sc.CONTENT_ELEMENT)) // SelectMany?
    .IncludeOptimized(re => re.SUBTITLE_CONTENT.Select(sc => sc.CONTENT_ELEMENT).Select(ce => ce.LANGUAGE)) // SelectMany?
    .Where(re => re.REPORT_ID == report.ID)
    .Load();

文档:EF+ Query IncludeOptimized