Foxtable(狐表)用户栏目专家坐堂 → 令人目瞪口呆的效率差别(有修正)


  共有47204人关注过本帖树形打印复制链接

主题:令人目瞪口呆的效率差别(有修正)

帅哥哟,离线,有人找我吗?
狐狸爸爸
  1楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:管理员 帖子:47497 积分:251403 威望:0 精华:91 注册:2008/6/17 17:14:00
令人目瞪口呆的效率差别(有修正)  发帖心情 Post By:2010/12/7 12:36:00 [只看该作者]

今天一个用户,希望在第三列中标出第一列有而第二列无的数据,假定第一列和第二列为整数型:

 


此主题相关图片如下:1502.gif
按此在新窗口浏览图片

 

测试文件,注意每次测试都重新打开项目,不要保存:

 

 

 下载信息  [文件大小:   下载次数: ]
点击浏览该文件:管理项目22.table

 


我给出的代码为:

 

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倍,效率差距之大,让人目瞪口呆。

原因应该找到了,为了验证我的想法,我另外写了两段代码测试,这次不使用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不再出现在同一个遍历语句中,而是在不同的遍历语句中出现。

 

 

[此贴子已经被作者于2010-12-7 23:31:50编辑过]

[本帖被加为精华]
 回到顶部
帅哥哟,离线,有人找我吗?
hnaysx
  2楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:婴狐 帖子:44 积分:903 威望:0 精华:0 注册:2010/9/17 21:54:00
  发帖心情 Post By:2010/12/7 12:56:00 [只看该作者]

用户已被锁定

 回到顶部
帅哥哟,离线,有人找我吗?
kylin
  3楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信 F6
等级:狐精 帖子:3036 积分:19223 威望:0 精华:2 注册:2008/9/1 7:50:00
  发帖心情 Post By:2010/12/7 13:23:00 [只看该作者]

这个鱼和熊掌不可得兼的经验,收藏!


 回到顶部
帅哥哟,离线,有人找我吗?
易服
  4楼 | QQ | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:三尾狐 帖子:787 积分:6349 威望:0 精华:0 注册:2008/9/1 8:26:00
  发帖心情 Post By:2010/12/7 13:41:00 [只看该作者]

有一按钮“编号”:自觉效率不高,能优化?

Dim str As String
For Each dr As DataRow In DataTables("申请表").DataRows
    str = "[乡名] = '" & dr("乡名") & "'And [村名] = '" & dr("村名") & "' And [组别] = '" & dr("组别") & "'"
    str = str  & "And  [单位(个人)] = '" & dr("单位(个人)") & "'  And  [法定代表人] = '" & dr("法定代表人") & "' And [_Identify] < " & dr("_Identify")
    dr("宗地序号") = Format(Tables("申请表").Compute("Count(乡名)",str)+1,"00")
Next
Tables("申请表").Sort = "法定代表人 DESC" '降序排列


 回到顶部
帅哥哟,离线,有人找我吗?
狐哥
  5楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:三尾狐 帖子:719 积分:5181 威望:0 精华:1 注册:2008/9/24 10:41:00
  发帖心情 Post By:2010/12/7 14:05:00 [只看该作者]

添加到集合再对比,真是高。受用了。


 回到顶部
帅哥哟,离线,有人找我吗?
migold
  6楼 | QQ | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:一尾狐 帖子:447 积分:4572 威望:0 精华:0 注册:2009/1/11 11:00:00
  发帖心情 Post By:2010/12/7 14:25:00 [只看该作者]

顶!试试去


 回到顶部
帅哥哟,离线,有人找我吗?
程兴刚
  7楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信 一级勋章
等级:超级版主 帖子:7258 积分:40773 威望:0 精华:16 注册:2008/8/31 23:23:00
  发帖心情 Post By:2010/12/7 14:33:00 [只看该作者]

收藏慢慢消化!

 回到顶部
帅哥哟,离线,有人找我吗?
狐狸爸爸
  8楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:管理员 帖子:47497 积分:251403 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2010/12/7 14:35:00 [只看该作者]

以下是引用易服在2010-12-7 13:41:00的发言:

有一按钮“编号”:自觉效率不高,能优化?

Dim str As String
For Each dr As DataRow In DataTables("申请表").DataRows
    str = "[乡名] = '" & dr("乡名") & "'And [村名] = '" & dr("村名") & "' And [组别] = '" & dr("组别") & "'"
    str = str  & "And  [单位(个人)] = '" & dr("单位(个人)") & "'  And  [法定代表人] = '" & dr("法定代表人") & "' And [_Identify] < " & dr("_Identify")
    dr("宗地序号") = Format(Tables("申请表").Compute("Count(乡名)",str)+1,"00")
Next
Tables("申请表").Sort = "法定代表人 DESC" '降序排列

 

可以这么改改看看:

 

Dim str As String
Dim Dic As New Dictionary(of DataRow, String)
For Each dr As DataRow In DataTables("申请表").DataRows
    str = "[乡名] = '" & dr("乡名") & "'And [村名] = '" & dr("村名") & "' And [组别] = '" & dr("组别") & "'"
    str = str  & "And  [单位(个人)] = '" & dr("单位(个人)") & "'  And  [法定代表人] = '" & dr("法定代表人") & "' And [_Identify] < " & dr("_Identify")
    dic.Add(dr,Format(DataTables("申请表").Compute("Count(乡名)",str)+1,"00"))
Next
For dr As DataRow In dic.Keys
    dr("宗地序号") = dic(dr)
Next


 回到顶部
帅哥哟,离线,有人找我吗?
易服
  9楼 | QQ | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:三尾狐 帖子:787 积分:6349 威望:0 精华:0 注册:2008/9/1 8:26:00
  发帖心情 Post By:2010/12/7 14:43:00 [只看该作者]

以下是引用狐狸爸爸在2010-12-7 14:35:00的发言:

 

可以这么改改看看:

 

Dim str As String
Dim Dic As New Dictionary(of DataRow, String)
For Each dr As DataRow In DataTables("申请表").DataRows
    str = "[乡名] = '" & dr("乡名") & "'And [村名] = '" & dr("村名") & "' And [组别] = '" & dr("组别") & "'"
    str = str  & "And  [单位(个人)] = '" & dr("单位(个人)") & "'  And  [法定代表人] = '" & dr("法定代表人") & "' And [_Identify] < " & dr("_Identify")
    dic.Add(dr,Format(DataTables("申请表").Compute("Count(乡名)",str)+1,"00"))
Next
For dr As DataRow In dic.Keys
    dr("宗地序号") = dic(dr)
Next


图片点击可在新窗口打开查看此主题相关图片如下:2010-12-7 14-42-11.png
图片点击可在新窗口打开查看

 回到顶部
帅哥哟,离线,有人找我吗?
狐狸爸爸
  10楼 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:管理员 帖子:47497 积分:251403 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2010/12/7 15:02:00 [只看该作者]

这都看不出来吗,我手误而已, 应该是:

 

For Each dr As DataRow In dic.keys

 


 回到顶部
总数 96 1 2 3 4 5 6 7 8 9 10 下一页