.NET 6升级至.NET 8后查询性能骤降,请求技术支援
以下是针对你遇到的查询性能下降问题的具体优化方案:
用Join替代Contains优化批量查询
当entities列表较大时,EF Core 8对Contains的SQL翻译可能生成低效的IN子句(尤其是参数数量过多时)。改用Join方式可以提升查询效率:public async Task<List<object>> GetWorkareaEntityPeriodListAsync(List<Guid> entities) { return await _dataBase.WorkareaEntityPeriods .Join(entities, period => period.WorkareaEntityPeriodId, id => id, (period, _) => period) .EntityProjectionGetDto() .ToListAsync(); }移除不必要的Distinct
如果WorkareaEntityPeriodId是表的主键,Where/Join后的结果本身就是唯一的,Distinct会额外增加数据库计算开销。先确认是否真的存在重复数据,若无则直接移除该调用。使用强类型DTO替代匿名类型
投影到匿名类型再转为object会导致装箱开销,且EF Core对强类型投影的SQL翻译通常更优化。定义对应的DTO类:public class WorkareaEntityPeriodDto { public Guid Id { get; set; } public string Name { get; set; } public Guid ClientId { get; set; } // 其他属性与投影字段一一对应 } public static IQueryable<WorkareaEntityPeriodDto> EntityProjectionGetDto(this IQueryable<WorkareaEntityPeriod> query) { return query.Select(s => new WorkareaEntityPeriodDto { Id = s.WorkareaEntityPeriodId, Name = s.WorkareaEntity.EntityName, ClientId = s.WorkareaEntity.ClientId, // 填充剩余属性 }); }检查并对比生成的SQL语句
对比.NET 6和.NET 8环境下生成的SQL,找出翻译差异。通过ToQueryString()获取SQL语句:var sql = _dataBase.WorkareaEntityPeriods .Where(x => entities.Contains(x.WorkareaEntityPeriodId)) .EntityProjectionGetDto() .ToQueryString();重点关注是否有多余的JOIN、嵌套子查询,或者IN子句参数数量过多的情况。
添加AsNoTracking禁用查询追踪
如果不需要对查询结果进行修改,禁用EF Core的实体追踪可以减少内存和CPU开销:return await _dataBase.WorkareaEntityPeriods .AsNoTracking() .Where(x => entities.Contains(x.WorkareaEntityPeriodId)) .EntityProjectionGetDto() .ToListAsync();优化数据库索引
确保以下字段存在合适的索引:WorkareaEntityPeriod.WorkareaEntityPeriodId(主键索引,通常已存在)- 关联外键字段:
WorkareaEntityPeriod.WorkareaEntityId、WorkareaEntityPeriod.WorkareaId、WorkareaEntityPeriod.EntitySettingsId
这些索引可以加速JOIN和关联查询的执行效率。
检查EF Core配置变化
确认是否开启了调试相关配置(如EnableDetailedErrors、EnableSensitiveDataLogging),这些在生产环境会增加性能开销,建议关闭。同时检查QuerySplittingBehavior等.NET 8新特性是否影响查询执行计划。
内容的提问来源于stack exchange,提问作者Aman Sinha

