【问题标题】:Linq 'contains' query taking too longLinq“包含”查询时间过长
【发布时间】:2012-05-02 12:49:25
【问题描述】:

我有这个问题:

var newComponents = from ic in importedComponents
                    where !existingComponents.Contains(ic)
                    select ic;

importedComponentsexistingComponents 的类型为 List<ImportedComponent>,并且仅存在于内存中(与数据上下文无关)。在本例中,importedComponents 有超过 6,100 个项目,existingComponents 有 511 个项目。

这个语句完成的时间太长(我不知道多长时间,我在 20 分钟后停止脚本)。我尝试了以下方法,但执行速度没有提高:

var existingComponentIDs = from ec in existingComponents
                           select ec.ID;

var newComponents = from ic in importedComponents
                    where !existingComponentIDs.Contains(ic.ID)
                    select ic;

任何帮助将不胜感激。

【问题讨论】:

    标签: asp.net linq


    【解决方案1】:

    问题是这个算法的二次复杂度。将所有现有组件ID 的ID 放入一个HashSet 并使用HashSet.Contains 方法。与列表中包含/任何内容的 O(N) 相比,它的查找成本为 O(1)。

    morelinq 项目包含一种方法,可以在一个方便的步骤中完成所有这些操作:ExceptBy。

    【讨论】:

      【解决方案2】:

      您可以使用Except 来获取设置差异:

      var existingComponentIDs = existingComponents.Select(c => c.ID); 
      var importedComponentIDs = importedComponents.Select(c => c.ID);
      var newComponentIDs = importedComponentIDs.Except(existingComponentIDs);
      var newComponents = from ic in importedComponents
              join newID in newComponentIDs on ic.ID equals newID
              select ic;
      foreach (var c in newComponents)
      { 
          // insert into database?
      }
      

      Why is LINQ JOIN so much faster than linking with WHERE?

      简而言之:Join方法可以建立一个哈希表作为索引来快速压缩两个表

      【讨论】:

      • 也可以做成一个可复用的函数 exceptBy。
      • @usr: Except 已经是一种可重用的方法,它接受任何类型的类型并且可以与默认值或custom equality comparer 一起使用,您还需要什么?很高兴您可以benefit from it's deferred execution(就像我在上面所做的那样)。
      • ExceptBy 会像 MinBy 与 Min 一样工作。它为您节省了投影步骤,并一步完成了您在此代码示例中所做的一切。
      • 请注意您使用的是参考比较,那么。如果两个不同的对象可以具有相同的 id,这种方法就会失效。我会确保情况并非如此。
      • @TimSchmelter Except() 查询耗时 00:00:00.0030001。相当大的进步:D。
      【解决方案3】:

      根据您提供的逻辑和数字,这意味着您在运行该语句时基本上执行了 3117100 次比较。显然,这并不完全准确,因为您的条件可能在遍历整个数组之前已经满足,但您明白我的意思。

      对于这么大的集合,您将希望使用一个集合,您可以在其中索引您的键(在本例中为您的组件 ID),以帮助减少搜索的开销。要记住的是,即使 LINQ 看起来像 SQL,这里也没有神奇的索引。主要是为了方便。事实上,我看过一些文章,其中链接查找实际上比蛮力查找要慢一些。

      编辑:如果可能的话,我建议您尝试使用 Dictionary 或 SortedList 来获取您的值。我相信任何一个都会有更好的查找性能。

      【讨论】:

        猜你喜欢
        • 2011-11-03
        • 1970-01-01
        • 1970-01-01
        • 2021-07-18
        • 2012-04-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多