使用LINQ填充父子结构的最优方法及性能疑问
关于LINQ父子结构填充的性能问题解答
首先明确:你担心的情况是对的——原代码里的嵌套查询会针对每个父节点遍历一次整个子表。如果有1000个父节点,就会执行1000次子查询,每次都全量扫描Children表,数据量越大,性能损耗越明显。
另外注意原代码里的语法错误:where条件中的判断应该用==,不是=,否则会编译失败。
优化方案:预分组子表
核心思路是先对子表按ParentId做一次分组,把结果存到字典里,之后遍历父节点时直接通过键值对快速查找,这样只需要遍历子表一次,整体时间复杂度从O(n*m)降到O(n+m)。
优化后的代码示例:
var ds = myDAL.GetDataSet("mySP"); var Parent = ds.Tables[0]; var Children = ds.Tables[1]; // 先将子表按ParentId分组,存入字典 var childGroups = Children.AsEnumerable() .GroupBy(c => c.Field<int>("ParentId")) .ToDictionary(g => g.Key, g => g.Select(c => new { Id = c.Field<int>("Id"), Name = c.Field<string>("Name") }).ToList()); // 遍历父节点,直接从字典取对应子项 var ParentChildren = from p in Parent.AsEnumerable() let parentId = p.Field<int>("Id") select new { Id = parentId, Name = p.Field<string>("Name"), Children = childGroups.TryGetValue(parentId, out var kids) ? kids : Enumerable.Empty<object>() };
优化说明
- 第一步的
GroupBy+ToDictionary只会执行一次,把所有子节点按父ID归类好。 - 遍历父节点时,通过
TryGetValue可以O(1)时间拿到对应的子节点集合,避免了重复扫描子表。 - 如果某个父节点没有子节点,用
Enumerable.Empty<object>()返回空集合,保证结构一致性。
内容的提问来源于stack exchange,提问作者Jahanzaib Muhammad
相关产品推荐
相关产品推荐

