在实体中查找对象和加载实体、Foreach 或在哪里使用 LinQ ON C# 的最佳性能?

Posted

技术标签:

【中文标题】在实体中查找对象和加载实体、Foreach 或在哪里使用 LinQ ON C# 的最佳性能?【英文标题】:Best performance for find objects in entities and load entities, Foreach or where with LinQ ON C#? 【发布时间】:2017-01-21 05:40:38 【问题描述】:

我需要关联一些实体。现在代码加载第一个实体,然后使用 foreach 循环进行迭代,如果当前行与另一个实体的记录的属性匹配,则搜索每条记录。 比如:

  foreach (Entity1 e1 in entity1List)
  
   foreach (Entity2 e2 in entity2List)
   
    if (e2.Id == e1.Id)
    
     //Do something
    
   
  

但是实体有很多记录,性能并不好。 我想提高尝试使用 linQ 搜索记录的速度。

var list = entity2List.Where(e2 => entity1.Any(e1 => e1.Id == e2.Id));

  foreach (Entity2 e2 in list )
  
  //Do something
  

但我不知道这是否真的有助于性能。另外我想知道在这种情况下加载实体的最佳模型。请提供一些建议或阅读链接或用于比较执行时间的工具。

我为每个实体的加载器使用了很多连接,但它们是分开的,因为在其他情况下测试行很多,并且在数据库上执行查询的时间太多,所以现在实体是独立的,我想通过代码创建依赖项。

【问题讨论】:

您可以随时分析两者并找出答案。 (提示:加载更少的记录比加载更多的记录总是会带来净收益)。 您不使用连接的任何原因? 并从 List 切换到 HashSet 或使用字典。从列表转移到 Hash/Dict 将大大加快所有查找速度 我为每个实体的加载器使用了很多连接,但它们是分开的,因为在其他情况下测试行很多,并且在数据库上执行查询的时间太多,所以现在实体是独立的,我想通过代码创建依赖关系 这些真的是带有实体化实体的列表,还是您的意思是数据库表? 【参考方案1】:

如果两个实体集都是真正的列表,则使用 LINQ Where 不会给您带来性能提升,因为它相当于您当前具有 O(M * N) 时间复杂度的线性搜索算法。

但是,您可以通过使用 LINQ GroupJoin 方法获得更好的 O(M + N) 时间复杂度算法(从而提高性能),该方法在内部使用非常有效的基于哈希的查找来关联两个序列:

var list = from e1 in entity1List
           join e2 in entity2List on e1.Id equals e2.Id into e2Group
           select new  e1, e2Group ;

foreach (var item in list)

    var e1 = item.e1;
    foreach (var e2 in item.e2Group)
    
        //Do something
    

如果您不需要嵌套的 foreach 循环进行处理,则可以使用 Join 代替,这样效率会更高:

var list = from e1 in entity1List
           join e2 in entity2List on e1.Id equals e2.Id
           select new  e1, e2 ;

foreach (var item in list)

    var e1 = item.e1;
    var e2 = item.e2;
    //Do something

【讨论】:

谢谢,我将我的方法的时间与 dotTrace 进行了比较,现在更好【参考方案2】:

正如@DavidL 所说,您可能想测试这两种解决方案,看看会发生什么。另一种选择是使用第一个集合进行哈希,然后通过键搜索。它应该会影响性能。

例子:

var e1ById = entity1List.GroupBy(x => x.Id).ToDictionary(x => x.Key); //you can skip the GroupBy if you know Id is a unique key)

foreach(var e2 in entity2List.Where(x => e1ById.ContainsKey(e2.Id)))

    //Do something

或者也许使用列表来存储密钥:

var keys = entity1List.Select(x => x.Id).Distinct().ToList();

foreach(var e2 in entity2List.Where(x => keys.Contains(x.Id))

    //Do something

无论如何,性能取决于初始收集长度,因此请尝试不同的解决方案并记下时间。

【讨论】:

【参考方案3】:

一般来说,如果性能是您的主要关注点,您通常最好编写自己的优化算法。由于开销,LINQ 肯定会比您的最佳算法慢。但是,LINQ 很优雅,对代码的可维护性非常有用。所以,选择权在你!

在这种特殊情况下,您可以使用 Intersect() 方法,该方法比您当前的实现更高效、更简单。

foreach (var element in entity1List.Intersect(entity2List))

// Do something

【讨论】:

以上是关于在实体中查找对象和加载实体、Foreach 或在哪里使用 LinQ ON C# 的最佳性能?的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate

实体框架不加载相关对象

hibernate的load和get有什么作用

求助myBatis sqlMap foreach 对象中的list传入,报错

JPA 懒加载问题

JAVA实体类对象怎么遍历