Linq除了在某些表上快速完成,但在其他表上没有

时间:2015-10-07 21:08:59

标签: vb.net linq

Dim dt As DataTable
Dim t1Except = t1.AsEnumerable().AsParallel().Except(t2.AsEnumerable().AsParallel(), DataRowComparer.[Default])

 If t1Except.Any() Then
     dt = t1Except.CopyToDataTable()
 Else
     dt = New DataTable
 End If

对两个具有相同结构的表(1列上的主键)执行包含200,000多行,并且在几秒钟内完成100多列。如果我在具有相同结构的另外两个表(5列上的主键)上使用相同的查询,其中包含350,000多行和15+列,则无法完成。

导致此问题的背景会发生什么?

2 个答案:

答案 0 :(得分:2)

DataRowComparer执行基于值的比较,因此对行内的实际数据执行m = magic(3) v = [3 4] [~,c] = size(m) i = 1:c i(ismember(m(:,1),v)) 检查会影响进行比较所需的时间。

许多事情会影响这些比较所花费的时间。例如:

  • 某些数据类型往往比其他数据类型更长。字符串通常需要比日期更长的时间进行比较。
  • 相同的字符串从Equals()返回需要更长的时间,与字符串的长度成比例。

因此,如果一组表具有大量相同的大字符串值,那么这可能是一种解释。有很多可能性,如果不了解表格中的数据,很难确定。

更新

进一步深入探讨:looks like Equals()使用Except(),使用HashSet<>()来实现GetHashCode()查询时间,但O(1) implements GetHashCode()只需查看第一列的值即可。

因为第一组表使用单个主键,所以最终会得到第一列,几乎为每个值生成唯一的哈希码。这使得查询花费DataRowComparer时间,这使O(1)花费Except()时间。

由于第二组表的主键有几列,我猜测第一列对于很多行都是重复的:对于每一行,它会对每一行进行O(n)检查使用相同的第一个值,然后对行中每列中的值进行Equals()检查,直到一个不匹配。随着第一行中唯一值的数量接近Equals(),查找复杂度接近1,使O(n)调用Except()操作。

要解决此问题,您可以根据O(n²)代码实现自己的IEqualityComparer<TRow> where TRow : DataRow,但会根据构成主键的所有列中的值创建哈希码。

另一种选择是使所有数据表中的第一行成为包含所有键值的对象;匿名类型适用于此,因为C#将为您自动实现DataRowComparerGetHashCode()。但是,如果您无法更改数据表的形状,则无法使用此功能。

答案 1 :(得分:0)

我改变了代码,不必处理如此多的行。我可以创建一个IQualityComparer但是现在这解决了这个问题。

Dim matchingRows As New List(Of DataRow)()
Dim comparer As IEqualityComparer(Of DataRow) = DataRowComparer.Default
Parallel.ForEach(t1.AsEnumerable(),
    Sub(r1 As DataRow)
        Dim pKey As New List(Of String)
        For Each column As DataColumn In t1.PrimaryKey
            pKey.Add(r1.Item(column.ColumnName).ToString())
        Next
        Dim foundRow As DataRow = t2.Rows.Find(pKey.ToArray)
        Dim bEqual = comparer.Equals(r1, foundRow)
        If (bEqual = True) Then
            SyncLock lockRows
                matchingRows.Add(r1)
            End SyncLock
        End If
    End Sub)
For Each item As DataRow In matchingRows
         t1.Rows.Remove(item)
Next