查询与赋值并存

以下内容需要使用List(集合)和Dictionary(字典), 其中Dictionary大家较少接触,如果对其不熟悉,请先行参考:Dictionary

在技术支持的过程中,我遇到一个用户,他希望在第三列中标出第一列有而第二列无的数据 ,其中第一列和第二列为整数型:

我给出的代码为:

For Each dr As DataRow In DataTables("表A").DataRows
    If
DataTables("表A").Find("第二列 = " & dr("第一列") ) Is Nothing Then
        dr("第三列") =
True
    Else

        dr("第三列") =
False
    End
If
Next

随后我进行了测试,在数据为1万行,第三列无数据的时候,执行上述代码花费了整整234秒,显然这样的效率是让人难以接受的。
上面的代码并没有什么特别的地方,在遍历过程中找出符合条件的行,并给此行的某列赋值而已。
那么到底是查找出了问题,还是赋值出了问题,以至于运行效率如此之低呢?
为了找出原因,我分别测试了查询和赋值:

测试查询的代码:

Dim v As Boolean
For Each
dr As DataRow In DataTables("表A").DataRows
    If DataTables(
"表A").Find("第二列 = " & dr("第一列")) Is Nothing Then
        v = dr(
"第三列")
    End If
Next

测试赋值的代码:

For Each dr As DataRow In DataTables("表A").DataRows
    dr
("第三列"
) = True
Next

出人意料的是,两段代码运行得都非常快,都在瞬间完成了。
那为什么第一段代码需要花费234秒?难道查询和赋值不能出现在同一个遍历语句中吗?
为此我改写了第一段代码,让查询和赋值分开进行,新的代码为:

Dim lst1 As New List(of DataRow)
Dim
lst2 AS New List(of DataRow)
For Each
dr As DataRow In DataTables("表A").DataRows
    If DataTables(
"表A").Find("第二列 = " & dr("第一列")) Is Nothing Then
        lst1
.Add(dr)
    Else

        lst2
.Add(dr)
    End If
Next
For Each
dr As DataRow In lst1
    dr
("第三列") = True
Next
For Each
dr As DataRow In lst2
    dr
("第三列") = False
Next

同样在数据为1万行,第三列无数据的时候,执行上述代码只花了0.8秒,比原来的234秒快了整整300倍,效率差距之大,令人瞠目。
原因应该找到了,为了验证我的想法,我打算对Compute方法进行测试,因为Compute在计算过程同样要进行查询。
于是我另外写了两段代码,这次不使用Find进行查询,而是使用Compute方法进行计算:

常规的代码,计算和赋值在同一个遍历语句:

Dim v As Double
For Each
dr As DataRow In DataTables("表A").DataRows
    v
= DataTables("表A").Compute("Count(第二列 )", "第二列 = " & dr("第一列"))
   
dr("第四列") = v

Next

估计效率更高的代码,计算和赋值分开进行:

Dim Dic As new Dictionary(of DataRow, Integer)
Dim
v As Double
For Each
dr As DataRow In DataTables("表A").DataRows
    v = DataTables("表A").Compute("Count(第二列 )", "第二列 = " & dr("第一列"))
    dic
.Add(dr, v
)
Next
For Each
dr As DataRow In dic.Keys
   
dr("第四列") = dic(dr)
Next

果不其然,经过测试,第二段比第一段同样快了整整300倍。

现在我总结一下,符合以下三个条件,会出现效率低下的情况:

1、用For语句遍历某个表。
2、遍历过程中会用Find或Select查询此表,或者用Compute方法统计此表。
3、遍历过程中会大量修改此表中某些行的值,被修改的行数越多,对于性能影响越大,如果被修改的行数很少,则几乎没有影响。

强调一下,上述三项中提到的表必须都是同一个表。
我们改写的代码之所以高效, 是因为改写后的代码使得上述2、3项不再出现在同一个遍历语句中,而是在不同的遍历语句中出现。


本页地址:http://www.foxtable.com/webhelp/topics/2225.htm