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+列,则无法完成。
导致此问题的背景会发生什么?
答案 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#将为您自动实现DataRowComparer
和GetHashCode()
。但是,如果您无法更改数据表的形状,则无法使用此功能。
答案 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