EF Core多层Include查询会议详情耗时过长优化及瓶颈排查咨询
一、查询与模型设计优化
- 补充缺失的导航属性加载
你当前的查询没有包含Meeting类下的Owner、Moderator、ReportWriter三个关联用户属性,如果后续代码访问了这三个属性,会触发N+1查询,每次访问都单独请求数据库,这是大概率的性能瓶颈来源。 - 拆分查询避免笛卡尔积
同时加载Agenda、Summonings两个集合导航属性时,EF Core默认会生成关联查询产生笛卡尔积,数据量会是多个集合的行数乘积,哪怕数据量小也会增加映射开销。EF Core 5及以上版本可以添加AsSplitQuery()将多个集合的加载拆分为独立查询,大幅降低冗余数据传输。 - 使用投影替代全实体加载
你当前返回完整实体,会加载ApplicationUser等模型中大量不需要的冗余字段,建议使用Select投影到DTO或匿名类,不需要手动写Include,EF Core会自动加载需要的关联字段,仅返回必要数据,性能提升非常明显,示例代码如下:
var meetingDto = await db.Meetings .Where(p => p.Id == parsedMeetingId) .Select(m => new { m.Id, m.Title, Agenda = m.Agenda.Select(a => new { a.Id, a.Title, Speakers = a.Speakers.Select(s => new { s.Id, s.IsCurrent, User = new { s.User.FirstName, s.User.LastName } }) }), Summonings = m.Summonings.Select(s => new { User = new { s.User.FirstName, s.User.LastName } }), Owner = new { m.Owner.FirstName, m.Owner.LastName }, Moderator = new { m.Moderator.FirstName, m.Moderator.LastName }, ReportWriter = new { m.ReportWriter.FirstName, m.ReportWriter.LastName } }) .FirstOrDefaultAsync();
- 增加无跟踪配置
如果该查询仅用于读取数据,不需要修改实体,添加AsNoTracking()关闭EF Core的实体状态跟踪,减少内存和CPU开销。 - 外键添加索引
给所有关联外键列添加数据库索引,包括AgendaItem.MeetingId、Speaker.AgendaItemId、Speaker.UserId、MeetingSummoning.MeetingId、MeetingSummoning.UserId,降低关联查询的开销。 - 优化Guid主键
如果使用的是无序Guid作为主键,且数据库主键为聚集索引,建议改为有序Guid(比如SQL Server的NEWSEQUENTIALID()),减少索引碎片,提升查询性能。
如果必须返回完整Meeting实体,优化后的查询参考:
Meeting meeting = await db.Meetings .AsNoTracking() .AsSplitQuery() .Include(a => a.Agenda) .ThenInclude(s => s.Speakers) .ThenInclude(u => u.User) .Include(s => s.Summonings) .ThenInclude(u => u.User) .Include(m => m.Owner) .Include(m => m.Moderator) .Include(m => m.ReportWriter) .FirstOrDefaultAsync(p => p.Id == parsedMeetingId);
二、潜在瓶颈排查
- 确认耗时位置
开启EF Core日志输出生成的原生SQL语句,将SQL直接放到数据库客户端执行,查看SQL本身的执行耗时。如果SQL执行慢则排查数据库层面问题,若SQL执行快(<10ms)则排查EF Core映射、配置层面的问题。 - 排查数据库配置
如果使用SQL Server Express,确认是否开启了AutoClose选项,该选项会在数据库闲置时自动关闭实例,下次查询需要重新启动,会导致查询耗时飙升。同时检查数据库文件是否存储在机械硬盘上,IO性能不足会拖慢查询速度。 - 排查EF Core配置
确认是否开启了延迟加载代理、全局查询过滤器、自定义查询拦截器等额外逻辑,这些逻辑会增加查询的额外开销。同时确认是否在Debug模式下运行,Debug模式的诊断逻辑会让EF Core执行速度比Release模式慢数倍,建议切换到Release模式复测。 - 排查设备资源占用
运行查询时查看任务管理器的资源占用,确认是否出现内存不足触发虚拟内存分页、CPU被其他进程占满、磁盘使用率100%的情况,笔记本的节能模式也可能导致CPU降频拖慢执行速度。 - 排查DbContext配置
如果DbContext注册为瞬态生命周期,每次查询都新建实例,若存在DbContext初始化时的重逻辑(比如大量模型配置、反射操作),也会导致每次查询耗时增加。
你提到的00:03异常耗时是EF Core一级缓存命中导致的,之前的查询已经把所有需要的实体加载到当前DbContext的跟踪缓存中,所以直接返回内存中的实体,不需要查询数据库。
内容的提问来源于stack exchange,提问作者Stian
相关产品推荐
相关产品推荐

