如何优化EF Core查询性能?现有代码加载耗时2分钟求改进
EF Core 查询性能优化方案
核心问题分析
原代码最大的性能瓶颈在于提前执行ToList()把全表数据加载到内存后再过滤,这会导致数据库返回大量不必要的数据,大幅增加网络传输和内存处理开销。此外还存在条件判断冗余、字符串处理未下推到数据库执行等问题。
优化后的代码实现
// 构建延迟执行的IQueryable,所有过滤逻辑下推到数据库处理 IQueryable<tablename> query = _context.tablename.AsNoTracking(); if (viewModel.CSku != null) { query = query.Where(x => x.CSku == viewModel.CSku); if (viewModel.CDesc != null) { var upperCDesc = viewModel.CDesc.ToUpper(); query = query.Where(x => EF.Functions.Like(x.CDesc.ToUpper(), $"%{upperCDesc}%")); } if (viewModel.WCode != null) { var upperWCode = viewModel.WCode.ToUpper(); query = query.Where(x => EF.Functions.Like(x.WCode.ToUpper(), $"%{upperWCode}%")); } } else { // 修复原代码中重复判断Length的冗余逻辑 bool hasNoPrimaryFilters = viewModel.Length == null && viewModel.Pattern == null && viewModel.Prefix == null && viewModel.Species == null; if (!hasNoPrimaryFilters) { if (viewModel.Length != null) { var trimmedLength = viewModel.Length.Trim(); query = query.Where(x => x.Length.Trim() == trimmedLength); } if (viewModel.Species != null) { var trimmedSpecies = viewModel.Species.Trim(); query = query.Where(x => x.Species.Trim() == trimmedSpecies); } if (viewModel.Pattern != null) { var trimmedPattern = viewModel.Pattern.Trim(); query = query.Where(x => x.Pattern.Trim() == trimmedPattern); } if (viewModel.Prefix != null) { var trimmedPrefix = viewModel.Prefix.Trim(); query = query.Where(x => x.Prefix.Trim() == trimmedPrefix); } } if (viewModel.WCode != null) { var upperWCode = viewModel.WCode.ToUpper(); query = query.Where(x => EF.Functions.Like(x.WCode.ToUpper(), $"%{upperWCode}%")); } } // 强制添加分页:避免一次性返回大量数据,根据业务需求调整页大小 // 若业务无需分页可移除,但建议保留以降低前端渲染压力 var paginatedResults = query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); return _mapper.Map<IEnumerable<tablenameViewModel>>(paginatedResults).ToList();
额外优化建议
- 数据库索引优化:为过滤字段(如
CSku、CDesc、WCode等)创建索引,针对Contains类模糊查询可考虑创建全文索引,进一步加速数据库查询。 - 简化字符串操作:如果数据库字段本身是大写存储,可去掉
ToUpper();若字段存储时已去除首尾空格,可去掉Trim(),减少不必要的计算。 - 直接投影映射:使用AutoMapper的
ProjectTo方法直接在数据库层面投影需要的字段,减少数据传输量:var viewModelQuery = query.ProjectTo<tablenameViewModel>(_mapper.ConfigurationProvider); var results = viewModelQuery.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); return results; - 监控生成SQL:开启EF Core日志功能查看生成的SQL语句,确认所有过滤逻辑都已下推到数据库,避免意外的客户端内存评估。
内容的提问来源于stack exchange,提问作者Gayu
相关产品推荐
相关产品推荐

