Foxtable(狐表)用户栏目专家坐堂 → 补充效率提升的另一种情况(有修正,从390秒提升到2秒,从2秒提升到不到1秒)


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

主题:补充效率提升的另一种情况(有修正,从390秒提升到2秒,从2秒提升到不到1秒)

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


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
补充效率提升的另一种情况(有修正,从390秒提升到2秒,从2秒提升到不到1秒)  发帖心情 Post By:2010/12/9 10:51:00 [显示全部帖子]

在C版的提醒下,补充一个效率提升的问题。

 

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

 

 下载信息  [文件大小:   下载次数: ]
图片点击可在新窗口打开查看点击浏览该文件:代码优化.rar

 

表结构如下图:

 


图片点击可在新窗口打开查看此主题相关图片如下:spximage.jpg
图片点击可在新窗口打开查看

 

希望在累计支出列计算出每个项目截止到当日为止的累计支出,有了上一次的经验,我想当然写出了这样这样的代码:

 

Dim s As Date = Date.Now()
Dim dic As New Dictionary(of DataRow, String)
Dim drs  As List(of DataRow)
For Each dr1 As DataRow In DataTables("表A").DataRows
    Dim Filter As String
    Filter = "项目 = '" & dr1("项目") & "' And 日期 <= #" & dr1("日期") & "#"
    dic.Add(dr1, DataTables("表A").Compute("Sum(支出)",Filter))
Next
For Each dr As DataRow In dic.Keys
    dr("累计支出") = dic(dr)
Next
Output.show(“执行时间:" & (Date.Now -s).TotalSeconds)

 

在一万行,累计支出列无内容的情况下,花了390秒。

这样的结果不仅让人难以接受,也出乎意料,为什么之前的招数完全失效了呢?

 

仔细分析一下可以看出,和之前的例子不同,上面的查询条件不全是“等于”比较,其中日期的比较是“小于等于”比较。
实际上在查询中,“等于”比较是最高效的,其他任何形式的比较效率都要低很多,也许真的就是这个“小于等于”比较影响了代码的执行效率。

但是“小于等于”比较是必须,不可能不用,那么我们唯一能着手的就是缩小“小于等于”比较的范围,改良后的代码为:

 

Dim s As Date = Date.Now()
Dim dic As New Dictionary(of DataRow, String)
Dim drs  As List(of DataRow)
For Each dr1 As DataRow In DataTables("表A").DataRows
    Dim dv As Date = dr1("日期")
    Dim sm As Double = 0
    drs = DataTables("表A").Select("项目 = '" & dr1("项目") & "'", "日期")
    For Each dr2 As DataRow In drs
        If dr2("日期") <= dv Then
            sm = sm + dr2("支出")
        Else
            Exit For
        End If
    Next
    dic.Add(dr1, sm)
Next
For Each dr As DataRow In dic.Keys
    dr("累计支出") = dic(dr)
Next
Output.show("执行时间" & (Date.Now -s).TotalSeconds)

 

同样在一万行,累计支出列无内容的情况下,上述代码花了2秒,看来之前的判断完全正确。

代码的原理是,先筛选出相同项目的行,再比较这些行的日期,从而大大缩小了日期“小于等于”比较的范围,如果你的项目是100个,那么比较范围就缩小了100倍,从而大大提升了代码的运行效率。

 

既然比较是影响效率的关键,于是我彻底改写代码,完全不用比较,最新的代码为:

 

Dim s As Date = Date.Now()
Dim drs As List(of DataRow) = DataTables("表A").Select("", "项目, 日期")
drs(0)("累计支出") = drs(0)("支出")
For i As Integer = 1 To drs.Count - 1
    If drs(i)("项目") = drs(i - 1)("项目") Then
        drs(i)("累计支出") = drs(i-1)("累计支出") + drs(i)("支出")
    Else
        drs(i)("累计支出") = drs(i)("支出")
    End If
Next
Output.show("执行时间:" & (Date.Now -s).TotalSeconds)

 

经过测试,处理1万行数据只用了0.9秒,又提升了一倍有余,而且代码更为简洁易懂。

 

代码的效率提升是没有定式的,实际编码的过程中只有用排除法,找出可能影响效率的因素,然后有针对性地改进。

[此贴子已经被作者于2010-12-9 14:09:28编辑过]

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


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2010/12/9 11:38:00 [显示全部帖子]

呵呵,帮助加进去了,示例文件就没有必要了吧。

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


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2010/12/9 13:47:00 [显示全部帖子]

其实最优化的代码应该是,现在不到一秒了:

 

Dim s As Date = Date.Now()
Dim drs As List(of DataRow) = DataTables("表A").Select("", "项目, 日期")
drs(0)("累计支出") = drs(0)("支出")
For i As Integer = 1 To drs.Count - 1
    If drs(i)("项目") = drs(i - 1)("项目") Then
        drs(i)("累计支出") = drs(i-1)("累计支出") + drs(i)("支出")
    Else
        drs(i)("累计支出") = drs(i)("支出")
    End If
Next
Output.show("执行时间:" & (Date.Now -s).TotalSeconds)


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


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2010/12/9 14:46:00 [显示全部帖子]

以下是引用mr725在2010-12-9 14:28:00的发言:

帮助中的 Select(Filter,Sort)  应加个说明:这个Filter是可选项,如果为空【""】时,上面的例子就是另一个应用了。。。

 

呵呵,帮助的第二个例子就是这样的啊


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


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2010/12/9 16:25:00 [显示全部帖子]

以下是引用blackzhu在2010-12-9 15:58:00的发言:

第一次代码:6秒多.

第二次代码:2秒多.

 

你的电脑太落伍啦,我测试的电脑都用了快3年了,居然速度是你的3倍。


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


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2010/12/9 16:43:00 [显示全部帖子]

以下是引用baoxyang在2010-12-9 16:28:00的发言:

针对SQL sever数据库有关提升方法呢?有那位高手提供最佳方法?

 

这是针对DataTable的,和数据源无关。

 


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


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2010/12/9 21:49:00 [显示全部帖子]

呵呵,还是SQL好,要知道保存1万行可是需要好多秒的。

这段SQL语句我勉强能看懂。

图片点击可在新窗口打开查看

 

 


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


加好友 发短信
等级:管理员 帖子:47448 积分:251054 威望:0 精华:91 注册:2008/6/17 17:14:00
  发帖心情 Post By:2011/11/17 10:33:00 [显示全部帖子]

呵呵,这都是很久以前的帖子了,早就加入帮助了啊。

 回到顶部