标题:再问个貌似很深,但别人觉得可能很浅的问题!
只看楼主
不懂就问呗
Rank: 2
来 自:遥远的回忆
等 级:论坛游民
帖 子:51
专家分:13
注 册:2007-12-16
 问题点数:0 回复次数:10 
再问个貌似很深,但别人觉得可能很浅的问题!
我现在发现一个问题,我要是搞出来个冗余量很大的数据库,一个表的DBF,就占42兆,CDX,16兆。记录数100多万。
这是我制定表结构的时候,没有合理安排,现在好多好多的重复记录。

我现在想依据这个表,编个小程序,把这个表中的记录,根据不重复的条件,录入到另个新表中(因为暂时不能删除现在这个表中的记录,旧表里可能有一些数据还有价值,盲目的删掉,在实际应用中,肯定不安全)

那么大家可以想像,我编的这个小程序,应该是依据一个判断是否重复的条件,然后,遍历整个表的一百多万条记录,把搜到的记录,存入新表,再将旧表中的所有与当前条件重复的,全加删除标记。
然后,再按下一个条件。。。。。。。。直到认为新表已经包括了旧表中所有的有用数据,并去掉了所有冗余。
=====================================================
到此,问题来了,我发现我的机器,在循环遍历上百万记录的时候,会很慢,遍历一千次,常常需要一个多小时。
我的是7200.9的IDE口硬盘,我分析主要问题,就是在硬盘的访问速度上!
可能是因为每次遍历表的所有记录的时候,都要从硬盘上表文件的开头,一直查到最后。这样比如查询遍历整个表一千次,就好像将这个40多兆的表文件(或再加个16兆的索引文件)读入到内存中的操作重复一千次。这肯定是很慢的,再快的机器,再快的硬盘,也就一万多转,也不可能比我的机器快多少倍。
我的问题就是-----有什么办法,把程序中用到的体积大的表,常驻内存,直到程序完成,再从内存卸下来?
因为现在都是G内存时代了,1G、2G、4G的内存,都不算希罕事了。把大体积的表调入内存,这样遍历一千次也好,遍历一万次也好,速度肯定要快过硬盘的十几倍甚至几十倍。就算是一千万条、一亿条记录的大表格,也不在话下。

但我就是不知道怎么让表常驻内存,然后,怎么样让命令或程序遍历的是内存中的表,而不是硬盘中的原始表(这个调入内存的表,不需要修改,仅是做为查询及反复遍历的根源,以取得需要数据存入新表,所以,从内存回写到硬盘的操作,可以暂时不考虑)?

以前我知道,有一类软件,是用内存模拟成磁盘,这样把表拷到“虚拟的盘”上,访问应该很快,但,这种第三方的软件,稳定性总是不太理想!!!! VFP自身,有这样的功能吗?

注:我以我现有所学,已经对程序的算法排查过了,不太可能是算法不理想的问题。再说,实际应用中,这种重复操作大体积表的情况也会有。所有,请各位高手, 把焦点集中在“如何将表调入内存”这个问题上,帮我分析解决。
谢谢!!
搜索更多相关主题的帖子: 记录 数据库 实际应用 
2007-12-26 15:21
hgfeng1984
Rank: 7Rank: 7Rank: 7
等 级:黑侠
威 望:5
帖 子:139
专家分:513
注 册:2006-3-26
得分:0 
先把大表拿来,100W的记录么,我们分成为10块,每块10W记录,处理起来会不会快点?
哇卡卡。。
2007-12-26 17:08
不懂就问呗
Rank: 2
来 自:遥远的回忆
等 级:论坛游民
帖 子:51
专家分:13
注 册:2007-12-16
得分:0 
卡卡哇。。
从头到尾,遍历一次,算一个条件判断结束,要是分十份完成,不是要生成10个新表了么?
再合成到一起,又要重新写程序,搞个同时遍历10个条的。。。。。。

拆了东墙补西墙的方法,貌似不是很聪明之举
哇嘎嘎。。。
2007-12-26 17:28
baichuan
Rank: 7Rank: 7Rank: 7
等 级:贵宾
威 望:37
帖 子:953
专家分:589
注 册:2006-3-13
得分:0 
把表备份一下,然后设定主键不能重复试试?

2007-12-27 08:20
Tiger5392
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:88
帖 子:2775
专家分:2237
注 册:2006-5-17
得分:0 
估计是算法的问题。我测试了一下797万记录,311476KB内容,找出598万条记录,需要2分钟。

感言:学以致用。 博客:http://www./blog/user14/65009/index.shtml email:Tiger5392@
2007-12-27 10:34
不懂就问呗
Rank: 2
来 自:遥远的回忆
等 级:论坛游民
帖 子:51
专家分:13
注 册:2007-12-16
得分:0 
。。。。。。都怪我,简单的问题,问复杂了!误导了Iiger5392兄。

你说的情况我明白,你的这种找出近600万条记录、耗时2分钟的操作,仅是用一个条件,操作一次。而我的情况,恰恰是把你的这一次操作,重复上千次甚至上万次。
+++++++++++++++++++++++++++++++++++++
我打个比方吧,我是说比如啊,大家不要笑我。
比如,我现在手里就有全中国人民的户籍库。那么户籍户,肯定会有姓名字段,而且,姓名中,包含赵、钱、孙、李。。。。。。等等的字符的记录,可以重复几十万,几百万甚至上亿条。
另外,我手里还有个汉字单字库,结构主要字段假设为:
word:即6000常用字再加几千甚至上万不常用字。(我们假设有一万个不重复的字)
onlyfn:逻辑,判断这个字,是否仅能当作姓氏在名字中出现。(假设有4000字,仅作为姓氏出现在姓名中)
bothfn:逻辑,判断这个字,是否是姓和名字都通用的字。(假设有2000字,可以兼作为姓氏出现在名字中)
&&那么还有4000字,无onlyfn和bothfn的标识,即只能作为名字部分出现
hjall:整形,用于存储统计整个户籍库中对应包含此字符的数目。
====================================
那么,现在我就编个循环,统计一下在户籍库里,含onlyfn的对应数目。
sele 2
use 字典
x=reccount()
sele 1
use 户籍
for i=1 to x
count for (b->onlyfn)$姓名 to y    &&姓名为户籍库中的人名字段
repl hjall with y in b
skip 1 in b
&&这种遍历,无论找到一条符合的记录,还是找到一百万条符合的记录,所花费的时间,应该、好像、大概、差不多,是相同。!!
====================================
按我这种笨方法,统计一个字在上亿条记录中出现的次数,把结果存到表中,再继续下一个循环,找下一个字出现的次数。重复几千次,甚至上万次。
这样的操作,重复下来,要多长时间呢?再延伸一下,刚才仅统计了姓氏,现在再统计一下仅能作为名字的字,在户籍表“姓名”字段出现的数目,再统计一下,仅能作为男性名字的字,在“姓名”中出现的数目,。。。。。。。

那我先来请教一下算法问题:上面所假设的每一个字的统计,是不是都要遍历一次户籍库?或者。。。。。。。。有什么更好的算法可以解决,是我不知道的?

那如果不是算法问题。。。。。。我说的这种情况,有什么快速的解决方案吗?
我所假设的,把户籍表驻入内存,供程序无数次的遍历,直到循环结束。这种方法有可行性吗?

再次强调,我上面举例,仅是假设。我知道中国人口超过10亿,一个VFP的表不可能存的下,但是日常工作中,难免会遇到处理几百万条记录的库表的情况。我也知道,这种大型的查询统计,可以采取分工合作的方法,用几台机器,分段查询再汇总到一起,但,我现在偏要一台机器工作(而且我目前也只有一台机器 )。

请各位:1、提出更好的算法,我才学VFP不久,可能是我自己把问题搞复杂了,正好借这个机会学习一下。
2、如果没有更好的算法,请大家提些可行的解决办法。我也开扩开扩视野。
2007-12-27 19:01
不懂就问呗
Rank: 2
来 自:遥远的回忆
等 级:论坛游民
帖 子:51
专家分:13
注 册:2007-12-16
得分:0 
不好,把老兄的名字打错了。。。
Tiger5392兄见谅啊,我可不是故意的
2007-12-27 19:04
不懂就问呗
Rank: 2
来 自:遥远的回忆
等 级:论坛游民
帖 子:51
专家分:13
注 册:2007-12-16
得分:0 
。。。。。语句中的count的条件,好像也不对

更正一下啊

count for (b->word)$姓名.and.(b->onlyfn) to y



现场即兴,想个示例,仅为说明我的意图,没想。。。。。露出了我的弱点
2007-12-27 19:09
Tiger5392
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:88
帖 子:2775
专家分:2237
注 册:2006-5-17
得分:0 
不好进一步回答你的问题,或者说你没有实质性问题。一般用Select-SQL语句处理。

感言:学以致用。 博客:http://www./blog/user14/65009/index.shtml email:Tiger5392@
2007-12-29 09:42
seek_gz
Rank: 1
等 级:新手上路
帖 子:2
专家分:0
注 册:2008-2-4
得分:0 
就楼主的 户籍-字典 问题,应该这样解决(这样的话,大表[户籍]仅仅循环了一次:
先在命令行中运行如下语句:
SELECT 0
USE 字典 EXCL
INDEX ON WORD TAG WD &&为姓氏汉字建立索引
USE
然后建立一个PRG文件,文件内容:
SELECT 0
USE 户籍
USE 字典 IN 0 ORDER WD
SELE 户籍
SCAN
C_XM=ALLTRIM(姓名)
FOR NI=1 TO LENC(C_XM) &&假定姓名都是中文,每字占用两个字符长
_CI=SUBSTR(C_XM,NI*2-1,2)
SELECT 字典
SEEK _CI
IF FOUND()
REPL  hjall with  hjall+1
ENDIF
ENDSC
另外,你地ONLYFN或者BOTHFN似乎是没用的,不适合这样设计.
2008-02-04 18:31



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-194411-1-1.html




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

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