You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core多JOIN查询性能极差,同语句在SSMS执行极快

EF Core中Include加载导航属性与投影查询的性能差异原因分析

问题场景

我有一个包含多个导航属性的实体,需要加载其中三个属性。最初编写的LINQ查询如下:

await _context.EventParticipant
              .Include(x => x.Employee)
              .Include(x => x.ExcuseDescription)
              .Include(x => x.RegistrationMethod)
              .Where(x => x.EventId == eventId)
              .ToListAsync();

该查询在获取约300行数据时出现严重性能问题,几乎无法完成。查看LINQ生成的SQL语句,在SSMS中执行耗时不到1秒。添加AsNoTracking()后性能无任何改善,调试显示查询执行+实体物化耗时约16秒。

尝试仅选择所需列,编写投影查询后性能提升显著,相同300行数据下耗时不到2秒:

await _context.EventParticipant
              .Where(x => x.EventId == eventId).AsNoTracking()
              .Select(participant => new EventParticipantViewModel()
                                     {
                                          EventId = eventId,
                                          EmployeeNumber = participant.EmployeeNumber,
                                          Department = participant.Employee.DepartmentName,
                                          FirstName = participant.Employee.Firstname,
                                          LastName = participant.Employee.Lastname,
                                          IsInvited = participant.IsInvited,
                                          ExcuseDescription = participant.ExcuseDescription.Description ?? null,
                                          RegisterMethod = participant.RegistrationMethod.Description ?? null,
                                      })
              .ToListAsync();

虽然两个查询生成的SQL差异极小,但性能差距巨大,以下是具体原因:

核心差异分析

  • 对象创建与数据量开销:
    使用Include时,EF Core会创建完整的EventParticipant实体及所有关联的Employee、ExcuseDescription、RegistrationMethod实体,每个实体包含其所有字段(即使你不需要)。这意味着要创建300个EventParticipant + 300个关联实体(共约1200个对象),且每个对象要填充大量无关属性。而投影查询仅创建300个EventParticipantViewModel,只填充你需要的几个属性,对象数量和数据填充量都大幅减少。

  • 物化流程复杂度:
    对于Include查询,EF Core需要处理多表Join后的结果集,将不同表的列映射到对应的实体对象,还要维护导航属性的引用关系(即使AsNoTracking,也需要解析结果集并拼接成完整的对象图)。这个过程涉及结果分组、实体匹配等额外逻辑,耗时较高。而投影查询是直接将SQL返回的列映射到ViewModel的属性,逻辑简单直接,不需要处理实体间的关联关系。

  • 内存处理与GC压力:
    大量完整实体的创建会占用更多内存,同时后续GC回收这些对象的开销也更大。投影查询的ViewModel体积小,内存占用低,GC压力也小,整体运行效率更高。

内容的提问来源于stack exchange,提问作者mobearette

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:36:34