繁体   English   中英

实体框架 6 - 查询性能

[英]Entity Framework 6 - Query Performance

我使用 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();

性能建议:

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

防止跟踪

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

参考: https ://learn.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()

此外,当我们使用 Select 时,我们可以删除.Include因为它在这里不会有任何效果。

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

免责声明:我是Entity Framework Plus项目的所有者

Query IncludeOptimized 功能允许使用 include 进行过滤,同时优化查询性能。

它通常会提高性能(将查询拆分为更小的查询)

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

暂无
暂无

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

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