使用内部包含来区分两个列表时的Linq性能

时间:2018-05-24 05:33:06

标签: c# performance linq

编辑01 :我似乎发现a solution (click for the answer)对我有用。通过预先计算然后应用.Except() extension method,从一小时到几小时;但是,如果其他人遇到此问题,请保持开放,如果其他人发现更好的解决方案

原始问题

我有以下一组查询,用于从源系统暂存的不同种类的对象,因此我可以保持同步并自己制作delta标记,因为源系统不能提供它,我们也不能建立或触摸它。

我获取内存中的所有数据然后例如执行此查询,在那里我查找在源系统中不再存在但在登台数据库中存在的对象 - 因此必须标记"删除&#34 ;.瓶颈是LINQ查询的第一部分 - 在.Contains()上,如何通过.Except()与自定义比较器一起改善它的性能? 或者我应该最好将它们放在散列列表中并执行比较?

问题是虽然我之后必须让阶段对象对它们进行一些属性转换,这似乎是最简单的解决方案,但不幸的是它在20k对象上非常慢

stagedSystemObjects.Where(stagedSystemObject => 
   !sourceSystemObjects.Select(sourceSystemObject => sourceSystemObject.Code)
        .Contains(stagedSystemObject.Code)
   )
   .Select(x =>
   {
       x.ActiveStatus = ActiveStatuses.Disabled;
       x.ChangeReason = ChangeReasons.Edited;
       return x;
   })
  .ToList();

2 个答案:

答案 0 :(得分:1)

我已经找到了解决这个问题的方法 - 这使得它只需要几秒钟而不是一小时的200k物体。

预先计算完成,然后应用.Except() extension method

所以不再"链接" linq查询,或在方法中执行.Contains ...但使其更简单"首先将两者都投影到string列表中,这样内部计算就不必在原始问题的示例代码中反复出现。

这是我的解决方案,目前令人满意。但是,如果有人想出一个精致/更好的解决方案,我就会离开这个!

var stagedSystemCodes = stagedSystemObjects.Select(x => x.Code).ToList();
var sourceSystemCodes = sourceSystemObjects.Select(x => x.Code).ToList();
var codesThatNoLongerExistInSourceSystem = stagedSystemCodes.Except(sourceSystemCodes).ToList();

return stagedSystemObjects
   .Where(stagedSystemObject => 
        codesThatNoLongerExistInSourceSystem.Contains(stagedSystemObject.Code))
   .Select(x =>
   {
       x.ActiveStatus = ActiveStatuses.Disabled;
       x.ChangeReason = ChangeReasons.Edited;
       return x;
   })
   .ToList();

答案 1 :(得分:1)

基于Yves Schelpe的回答。我做了一些调整以使其更快。 基本想法是取消前两个ToList并使用PLINQ。看看这个帮助

            var stagedSystemCodes = stagedSystemObjects.Select(x => x.Code);
            var sourceSystemCodes = sourceSystemObjects.Select(x => x.Code);
            var codesThatNoLongerExistInSourceSystem = stagedSystemCodes.Except(sourceSystemCodes).ToArray();

            var y = stagedSystemObjects.AsParallel()
               .Where(stagedSystemObject =>
                    codesThatNoLongerExistInSourceSystem.Contains(stagedSystemObject.Code))                  
               .Select(x =>
               {
                   x.ActiveStatus = ActiveStatuses.Disabled;
                   x.ChangeReason = ChangeReasons.Edited;
                   return x;
               }).ToArray();

请注意,PLINQ可能只适用于具有多核CPU的计算限制任务。在其他情况下,它可能会使事情变得更糟。