提问人:CrazyEight 提问时间:1/21/2020 更新时间:1/21/2020 访问量:2402
实体框架 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();
答:
性能建议:
- 防止跟踪。以只读模式查询。
- 防止在一次查询中获取过多数据。尝试对它进行分页。
- 防止包含。查询的 s 太多,导致性能不佳。
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 的建议之外,我还想添加一些建议,将其拆分为几个不同的查询。EF 将能够跟踪同一 .作为一般经验法则 - 不要在同一查询中使用三个以上的。此外,请确保数据库中每个生成的 JOIN 都有一个索引。Includes()
DBContext
Includes()
为此,除了导航属性之外,还必须公开实体中的 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 项目的所有者
查询 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();
评论
AsNotracking()
Select
Proxies
LazyLoading