带版本化嵌套实体的LINQ查询生成慢SQL问题及性能优化咨询
优化LINQ查询性能的解决方案
你的问题根源在于原LINQ查询每次过滤、排序时都重复执行子查询获取最新的order和term记录,导致生成的SQL多次关联同一张表,而且关联term时逻辑冗余。我们可以模仿你手动SQL的思路,先预获取每个orderHeader对应的最新order,以及每个termHeader对应的最新term,再进行关联查询,这样就能大幅减少表关联次数,提升性能。
具体优化步骤
1. 预定义最新order和term的子查询
先使用窗口函数(ROW_NUMBER())获取每个分组下的最新记录,和你手动SQL的逻辑完全对齐:
// 获取每个orderHeader对应的最新order记录 var latestOrders = _DbContext.order .AsNoTracking() .Select(o => new { o.id, o.orderHeaderId, o.name, o.notes, o.termHeaderId, o.createdDate, RowNum = EF.Functions.RowNumber().Over( PartitionBy: o.orderHeaderId, OrderBy: o.createdDate descending) }) .Where(o => o.RowNum == 1); // 获取每个termHeader对应的最新term记录 var latestTerms = _DbContext.term .AsNoTracking() .Select(t => new { t.id, t.termHeaderId, t.name, t.createdDate, RowNum = EF.Functions.RowNumber().Over( PartitionBy: t.termHeaderId, OrderBy: t.createdDate descending) }) .Where(t => t.RowNum == 1);
2. 关联主查询并应用过滤/排序
将orderHeader和预定义的最新order、term关联,后续的过滤和排序都基于关联后的字段,避免重复子查询:
string _word = "%123%"; bool _searchOrderName = true; bool _searchOrderNotes = true; bool _searchTermName = true; int _sort = 0; // 构建主查询:关联orderHeader、最新order、最新term var query = from oh in _DbContext.orderHeader.AsNoTracking() join lo in latestOrders on oh.id equals lo.orderHeaderId join lt in latestTerms on lo.termHeaderId equals lt.termHeaderId where oh.isDeleted != true select new { OrderHeader = oh, LatestOrder = lo, LatestTerm = lt }; // 应用过滤条件 if (_searchOrderName) { query = query.Where(x => EF.Functions.Like(x.LatestOrder.name, _word)); } if (_searchOrderNotes) { query = query.Where(x => EF.Functions.Like(x.LatestOrder.notes, _word)); } if (_searchTermName) { query = query.Where(x => EF.Functions.Like(x.LatestTerm.name, _word)); } // 应用排序 query = _sort switch { // 可根据需求扩展其他排序分支 _ => query.OrderByDescending(x => x.LatestOrder.name) }; // 获取总条数(生成的SQL性能与你手动编写的一致) var totalCount = await query.CountAsync();
优化效果说明
- 这个LINQ查询生成的SQL会和你手动编写的逻辑完全匹配:只关联
order和term各一次,通过窗口函数预取最新记录,彻底解决了原查询中多次子查询、重复关联表的问题。 - 过滤和排序操作都基于已经关联好的最新记录,不会重复触发子查询,大幅降低数据库的查询开销,计数操作的耗时会降到0.2-0.3秒的水平。
内容的提问来源于stack exchange,提问作者wittabeast
相关产品推荐
相关产品推荐

