foreach循环添加数据库条目到结果列表的更高效实现方案有哪些?
高性能实现匹配添加的方案
首先先指出你现有代码的两个核心问题:
- 编译错误:你声明的
resultList是List<SomeType1>类型,Add()方法只能传入单个SomeType1对象,但foundItems是IEnumerable<SomeType1>集合,直接运行会编译不通过,需要改用AddRange()方法添加集合元素。 - 性能缺陷:当前写法的时间复杂度为
O(n*m)(n为本地集合长度,m为数据库查询集合长度),每次循环都要完整遍历一次databaseList匹配Id,数据量稍大时性能会出现明显下滑。
优化方案(时间复杂度降至O(n+m))
核心思路是提前为databaseList构建Id索引,把循环内的遍历匹配改成O(1)的哈希查找,仅需要遍历两个集合各一次即可完成操作。
方案1:通用场景(支持同Id匹配多条数据)
如果databaseList中可能存在同Id对应多条数据的情况,使用Lookup构建索引最方便:
// 第一步:仅遍历一次databaseList,构建Id到对应实体的哈希索引 var dbIdLookup = databaseList.ToLookup(x => x.Id); List<SomeType1> resultList = new List<SomeType1>(); foreach (var localItem in localSysList1) { // 直接查哈希索引拿到匹配结果,批量添加到结果集 resultList.AddRange(dbIdLookup[localItem.Id]); }
如果偏好LINQ的简写写法,也可以一行完成:
var resultList = localSysList1.SelectMany(localItem => dbIdLookup[localItem.Id]).ToList();
方案2:Id唯一场景(性能略优)
如果可以保证databaseList中Id不会重复,用Dictionary构建索引内存占用更低、查找效率更高:
// 构建Id到实体的字典索引 var dbIdDict = databaseList.ToDictionary(x => x.Id); List<SomeType1> resultList = new List<SomeType1>(); foreach (var localItem in localSysList1) { if (dbIdDict.TryGetValue(localItem.Id, out var matchedItem)) { resultList.Add(matchedItem); } }
特殊场景:databaseList还未查询到内存(EF Core场景)
如果你的databaseList是还没执行拉取操作的EF CoreIQueryable,不要先把全表数据查到内存再过滤,直接把本地Id集合传到数据库层面过滤,性能会高很多:
// 提取本地要匹配的Id集合 var needMatchIds = localSysList1.Select(x => x.Id).ToList(); // EF会自动生成带IN语句的SQL,仅查询匹配Id的数据,避免拉取全表 var resultList = await dbContext.YourDbSet.Where(x => needMatchIds.Contains(x.Id)).ToListAsync();
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

