| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 3438 人关注过本帖, 2 人收藏
标题:提高代码的运行速度
取消只看楼主 加入收藏
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
结帖率:88.24%
收藏(1)
已结贴  问题点数:100 回复次数:16 
提高代码的运行速度
电脑配置
图片附件: 游客没有浏览图片的权限,请 登录注册

VFP9 汉化版 7423
这是一门科目的考试成绩,保存在JMSS1字段中,共有8题(各有129403条记录),以逗号分隔,成绩不但有0分、3分,还有带小数位的成绩(如1.5分),见下图
图片附件: 游客没有浏览图片的权限,请 登录注册

2,2,2,2,0,3,3,3 分别代表每题得到的分数。
根据这台电脑的配置情况,获取这门科目8题的有关数据耗时4秒。
要求:1、获取每题分值对应的人数,效果图如下
图片附件: 游客没有浏览图片的权限,请 登录注册

      2、尽最大能力缩短程序运行的时间

附上运行代码及相关数据:
sp.rar (451.53 KB)

程序代码:
t1 = SECONDS()
CLOSE DATABASES 
USE 选择\sp ALIAS aa
ln = OCCURS(",", jmss1) + 1 && 获取题目的数量
FOR lnj = 1 TO ln
    CREATE CURSOR fz (nfz n(4, 2), nsl I) && 保存分值的
    INDEX on nfz TAG fz
    SELECT VAL(GETWORDNUM(jmss1, lnj, ",")) nfz FROM aa INTO CURSOR temp
    SCAN 
        IF SEEK(temp.nfz, "fz", "fz") = .T.
            REPLACE nsl WITH nsl + 1 IN fz
        ELSE
            INSERT INTO fz VALUES (temp.nfz, 1)
        ENDIF
    ENDSCAN
ENDFOR 
MESSAGEBOX(SECONDS() - t1)
SELECT fz
BROWSE 


收到的鲜花
  • schtg2021-04-03 05:49 送鲜花  2朵  
搜索更多相关主题的帖子: 运行 速度 代码 temp 获取 
2021-03-31 20:44
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
如果不用临时表,用字符,时间可以缩短为3.3秒,于事无补。

坚守VFP最后的阵地
2021-04-01 07:58
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
1 楼代码变更如下
程序代码:
T1 = SECONDS()
CLOSE DATABASES 
USE 选择\sp ALIAS aa
ln = OCCURS(",", jmss1) + 1 && 获取题目的数量
FOR lnj = 1 TO ln
    CREATE CURSOR fz (nfz n(4, 2), nsl I) && 保存分值的
    INDEX on nfz TAG fz
    SELECT aa
    SCAN 
        IF SEEK(VAL(GETWORDNUM(aa.jmss1, lnj, ",")), "fz", "fz") = .T.
            REPLACE nsl WITH nsl + 1 IN fz
        ELSE
            INSERT INTO fz VALUES (VAL(GETWORDNUM(aa.jmss1, lnj, ",")), 1)
        ENDIF
    ENDSCAN
ENDFOR 
MESSAGEBOX(SECONDS() - T1)

发本帖的原意是,在不使用SQL命令查询的前提下,VFP命令得到结果的极限运行时间。
SUBSTR()与GETWORDNUM()在截取字符串时各有优势,如果字符串中子字符串的宽度是一样的(以分隔符分隔的10000个子字符串),GETWORDNUM()截取子字符串所需时间是SUBSTR()截取子字符串所需时间的60倍(至少);如果字符串中子字符串的宽度是不一样的(如本题中分值带有小数位),GETWORDNUM()的优势就明显了。
如:
2,2,2,2,0,1.5,3,3
2,2,2,2,0,3,1.5,3
2,2,2,2,0,3,3,1.5
因为你不知道带小数位的分值出现在那一题中,所以用SUBSTR()截取子字符串很麻烦。

[此贴子已经被作者于2021-4-1 11:17编辑过]


坚守VFP最后的阵地
2021-04-01 11:06
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
以下是引用瓜瓜1990在2021-4-1 10:41:26的发言:

直接用group by不一样么,快不少
t1 = SECONDS()
CLOSE DATABASES
USE sp ALIAS aa
ln = OCCURS(",", jmss1) + 1 && 获取题目的数量
FOR lnj = 1 TO ln
    temp="temp"+"_"+TRANSFORM(m.lnj)
    SELECT VAL(getwordnum(jmss1,m.lnj,",") )nfz ,COUNT(*) as nrs FROM aa INTO CURSOR (temp) GROUP BY 1
ENDFOR
MESSAGEBOX(SECONDS() - t1)
BROWSE

谢谢瓜瓜1990

坚守VFP最后的阵地
2021-04-01 11:09
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
以下是引用mywisdom88在2021-4-1 11:49:08的发言:

数据量不够大,效果不明显的,才10W的数据,要100W去,估计很明显;因为各人的电脑配置不相同

代码运行时间以我的电脑为准

坚守VFP最后的阵地
2021-04-01 12:06
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
6楼的代码应该比5楼的代码运行慢

坚守VFP最后的阵地
2021-04-01 14:41
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
以下是引用mywisdom88在2021-4-1 13:40:57的发言:

把程序放到C盘,变成144秒(C盘是固态盘,I是以前的机械盘)
把这个,去掉,就变成1.6秒,速度和写盘,有很大关系
        IF SEEK(VAL(GETWORDNUM(aa.jmss1, lnj, ",")), "fz", "fz") = .T.
      *      REPLACE nsl WITH nsl + 1 IN fz
        ELSE
      *     INSERT INTO fz VALUES (VAL(GETWORDNUM(aa.jmss1, lnj, ",")), 1)
        ENDIF
********************************


SET DEFAULT TO c:\abc
T1 = SECONDS()
CLOSE DATABASES
USE 选择\sp ALIAS aa
ln = OCCURS(",", jmss1) + 1 && 获取题目的数量
FOR lnj = 1 TO ln
    CREATE CURSOR fz (nfz n(4, 2), nsl I) && 保存分值的
    INDEX on nfz TAG fz
    SELECT aa
    SCAN
        IF SEEK(VAL(GETWORDNUM(aa.jmss1, lnj, ",")), "fz", "fz") = .T.
            REPLACE nsl WITH nsl + 1 IN fz
        ELSE
            INSERT INTO fz VALUES (VAL(GETWORDNUM(aa.jmss1, lnj, ",")), 1)
        ENDIF
    ENDSCAN
ENDFOR
MESSAGEBOX(SECONDS() - T1)

是不是说固态盘影响数据的写入

坚守VFP最后的阵地
2021-04-01 14:51
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
以下是引用mywisdom88在2021-4-1 17:21:14的发言:

我电脑WIN7 64,8G内存
但不知道,为什么这么慢
1个120G固态硬盘,做C盘,其他的是,D,E,F,G,I是机械硬盘

对于硬件我是绝对外行

坚守VFP最后的阵地
2021-04-01 17:46
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
以下是引用ycvf在2021-4-1 17:44:23的发言:

这个函数GETWORDNUM(jmss1, lnj, ",")没见过,有知道的吗、

VFP9 版本中的一个函数,大体意思:从一个字符串中返回指定单词。

坚守VFP最后的阵地
2021-04-01 17:48
sdta
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:江苏省连云港市
等 级:版主
威 望:335
帖 子:9809
专家分:26987
注 册:2012-2-5
收藏
得分:0 
以下是引用厨师王德榜在2021-4-1 17:15:35的发言:

我的代码,按照要求不用任何Select ... 语句 ,另辟蹊径用了字典对象,供大家参考:
IF NOT USED('sp') THEN
    USE "C:\sp.dbf" IN 0 EXCLUSIVE  &&  改成你的路径
ENDIF
LOCAL icnt as Integer ,ii as Integer
LOCAL ckey as String ,str1 as String
LOCAL time11 as Datetime ,time22 as Datetime

IF  USED('result1') THEN
    USE IN result1
ENDIF

LOCAL  oDic As Object
oDic = CreateObject("Scripting.Dictionary")
time11 = SECONDS()
SELECT sp
GO TOP
SCAN
    str1 = ALLTRIM(sp.jmss1)
    icnt = ALINES(arr2,str1,1,",")
    FOR ii =1 TO icnt
        ckey = LTRIM(STR(ii)) - "_" - arr2(ii)
        IF odic.Exists(ckey) THEN
            odic.Item(ckey) = odic.Item(ckey) + 1
        ELSE
            odic.Add( ckey,1) &&
        ENDIF     
    ENDFOR

ENDSCAN

DIMENSION arrKey(1) as String
arrKey =odic.Keys

CREATE CURSOR result1 (第几题 c(4) , 分值 c(4),次数 i )
FOR ii = 1 TO odic.Count  &&
*!*        tmp11 = LEFT(arrKey(ii), AT('_',arrKey(ii)) -1)
*!*        tmp22 = SUBSTR(arrKey(ii), AT('_',arrKey(ii)) +1)
*!*        tmp33 = odic.Item(arrKey(ii))
   
    INSERT INTO result1 (第几题  , 分值 ,次数  ) ;
        VALUES ( LEFT(arrKey(ii), AT('_',arrKey(ii)) -1),  ;
                SUBSTR(arrKey(ii), AT('_',arrKey(ii)) +1), ;
                odic.Item(arrKey(ii)) )
ENDFOR
time22 = SECONDS()
odic.RemoveAll
RELEASE oDic
SELECT result1
INDEX on 第几题 + 分值 TO 'C:\ind12'   &&  改成你的路径

BROWSE TITLE "总耗时" +  LTRIM(STR(time22 - time11 ,14,4 ))

在我的电脑上运行结果:

独辟蹊径,别具一格,方法学习了,速度不理想。

[此贴子已经被作者于2021-4-1 18:34编辑过]

收到的鲜花
  • 瓜瓜19902021-04-01 20:37 送鲜花  1朵  

坚守VFP最后的阵地
2021-04-01 18:31
快速回复:提高代码的运行速度
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.018562 second(s), 11 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved