你把问题说得复杂化了,依我的理解:(下面引用原话)问题很简单,远程机器上是Sql Server 2000,本地机器上是Access 2000,现在已经完成的部分是:远程机器上读取一个表的数据,转为流,压缩,通过Socket传送到本地,解压,转为一个记录集,现在使用类似DBGrid的感知控件可以读出其中数据,但用户要求对这个数据集进行查询,我不会对数据集使用SQL,准备存储到Access 2000中再处理。现在的问题是存储过程非常慢,5000-10000条数据大概要两分钟,而使用Access 2000的数据导入功能只需要一秒附近。也就是说解压后的数据如何在短时间内导入Access, 即本地数据导入本地Access 数据库!只要不是单条循环处理就肯定不用2分钟,最简单的办法,用BatchMove好了,5000-10000条记录最多只要几秒。
你用我的代码试试: 我的赛杨333录入4600条记录用了6秒钟. 做了一个通用的程序: http://netroom.hbu.edu.cn/personal/mudeen/quickcopy.exe 源码如下: http://netroom.hbu.edu.cn/personal/mudeen/quickcopy.zip 关键代码如下: if fileexists('c:\12.dat') then begin
adodataset2.LoadFromFile('c:\12.dat'); end else exception.Create('尚无本地数据包,请重新下载远程数据库'); // button3.Enabled:=gotdata; adoquery1.Connection:=adoconnection2; adoquery1.Close; with adoquery1 do begin locktype:=ltBatchOptimistic; sql.Clear; sql.Add(adodataset1.CommandText+' where 0=1'); // showmessage(sql.Text); open; end; begin application.ProcessMessages; adodataset2.DisableControls; while not adodataset2.eof do begin adoquery1.Insert; for i:=0 to adodataset2.FieldCount-1 do adoquery1.Fields.Fields[i].Value:=adodataset2.Fields.Fields[i].Value ; adodataset2.Next; end; adodataset2.First; edit2.Text:=datetimetostr(time); adodataset2.EnableControls; adoquery1.UpdateBatch(arall); end;
johnson,实在没有办法我也只能用batchmove了,当时不考虑这个的原因是第一batchmove作我的数据导入也不是几秒钟就能完成的,第二要求客户端又要安装BDE,我的客户分布得很广,绝大多数都是在城市近郊,55555555,要发布或者更新一次软件非常困难,客户素质又极低,不可能要求他们自己做。所以我这里的问题其实就是希望能得到代码调用SQL Server 2000的导出过程和Access 2000得导入过程,并不是说没有方案解决。正如你所说,如果按照单条录入的话,效率怎么都不可能高,那么就没有人考虑过为什么Access或SQL Server得导入导出效率为 什么这么高,我们是否可以利用呢?这些天我最大感触是项目和学习是不一样的, 学习的时候也许只要有解决方案就可以,而项目更多要考虑效率等其他一些客观问题。
SQL Server 道出: backup database to disk='d:\abc.bak' with replace
man8888,如何把备份出来的数据库用代码还原到Access中?
用DTS作数据导入应是最快的办法, 我建议你在打开SQL事件探查器,然后用SQL Server 2000的DTS向导,将SQL Server中的数据导入Access 2000导入完成后,逐条copy SQL事件探查器中记录的SQl执行语句。经过整理后,就可由用户自己调用这些SQL代码。 很多SQL的功能都能用这种办法实现。
你的客户应该不会一天的数据量就有一万多条记录吧,为什么不只追加自上次追加后更新过的记录呢。在远程服务器的数据表中增加一个LastChangeTime(最后修改时间)字段,读取远程数据表的DataSet的查询语句这么写: select * from SqlTable where LastChangeTime>上次取得数据时间
Select *into yy from xx 在SQL server中建立连接服务器这样很快的! 但是好像要标准服务器板以上才支持!
manboo,不好意思,我知道的select * into yy from xx好像一般做创建新表用。笑哥哥,我知道SQL导出有一个library可以用,但Access导入的com或者api我就没有一点思路了,这就是这次想问的主要目的。用BatchMove也要20秒,可能是我机器不好,用batchmove的时候其他基本都停了,而Access得导入...对别的没有什么影响,我想做程序,无非就是想学东西,所以来问了,呵呵 。
不可思议的执行效率 下面的这段代码(在内存中为数据集增加10000条记录)执行时间要30多秒 procedure TForm1.BitBtn2Click(Sender: TObject); var aTimeS,aTimeE:double; begin if not AdoDataSet1.Active then AdoDataSet1.Active :=True; ClientDataSet1.DisableControls; ClientDataSet1.First; aTimeS:=GetTickCount(); while not ClientDataSet1.Eof do begin AdoDataSet1.Insert; AdoDataSet1.FieldByName('Field1').AsString:=ClientDataSet1.FieldByName('Field1').AsString; AdoDataSet1.FieldByName('Field2').AsString:=ClientDataSet1.FieldByName('Field2').AsString; AdoDataSet1.FieldByName('Field3').AsString:=ClientDataSet1.FieldByName('Field3').AsString; AdoDataSet1.FieldByName('Field4').AsString:=ClientDataSet1.FieldByName('Field4').AsString; AdoDataSet1.FieldByName('Field5').AsString:=ClientDataSet1.FieldByName('Field5').AsString; AdoDataSet1.FieldByName('Field6').AsString:=ClientDataSet1.FieldByName('Field6').AsString; AdoDataSet1.FieldByName('Field7').AsString:=ClientDataSet1.FieldByName('Field7').AsString; AdoDataSet1.FieldByName('Field8').AsString:=ClientDataSet1.FieldByName('Field8').AsString; AdoDataSet1.FieldByName('Field9').AsString:=ClientDataSet1.FieldByName('Field9').AsString; AdoDataSet1.Post; ClientDataSet1.Next; end; ATimeE:=GetTickCount(); Label1.Caption :=FloatToStr((ATimeE-aTimeS)/1000); end; 最后的统计时间是37.354而下面这几行代码只是调用UpdateBatch将数据存盘,竟然要10多分钟的时间 procedure TForm1.BitBtn3Click(Sender: TObject); var ATimeS,ATimeE:double; begin ATimeS:=GetTickCount(); AdoDataSet1.UpdateBatch(arAll); ATimeE:=GetTickCount(); Label2.Caption :=FloatToStr((ATimeE-aTimeS)/1000); end; 统计的结果是598.912大家看看是什么原因,只是一个UpdateBatch啊,竟然要这么长时间
Insert into Accesstable select * from SQLTable
我想SQL的导入工具远离也是这样的,你是先把SQL上的表格取过来,在本地存放成文件,还要压缩解压,然后再放到数据集,再导入到Access,这样走了很多弯路,当然会很费时间,为什么不直接在两个数据源之间导入呢?这样一定会很快的,至于实现过程,我想对你来说应该是很简单了吧。
光读个一万条记录出来我看过,记录集的大小大概是5-600k,如果不压缩就传,
基本上是一分多钟,客户不接受。另外,我现在的实现方式就是为了节省服务器资源,提高效率,全部都在内存中
操作,读了SQL后我把内存流直接压缩就传走了。
数据库!只要不是单条循环处理就肯定不用2分钟,最简单的办法,用BatchMove好了,5000-10000条记录最多只要几秒。
我的赛杨333录入4600条记录用了6秒钟.
做了一个通用的程序:
http://netroom.hbu.edu.cn/personal/mudeen/quickcopy.exe
源码如下:
http://netroom.hbu.edu.cn/personal/mudeen/quickcopy.zip
关键代码如下:
if fileexists('c:\12.dat') then
begin
adodataset2.LoadFromFile('c:\12.dat');
end
else
exception.Create('尚无本地数据包,请重新下载远程数据库');
// button3.Enabled:=gotdata;
adoquery1.Connection:=adoconnection2;
adoquery1.Close;
with adoquery1 do
begin
locktype:=ltBatchOptimistic;
sql.Clear;
sql.Add(adodataset1.CommandText+' where 0=1');
// showmessage(sql.Text);
open;
end;
begin
application.ProcessMessages;
adodataset2.DisableControls;
while not adodataset2.eof do
begin
adoquery1.Insert;
for i:=0 to adodataset2.FieldCount-1 do
adoquery1.Fields.Fields[i].Value:=adodataset2.Fields.Fields[i].Value ;
adodataset2.Next;
end;
adodataset2.First; edit2.Text:=datetimetostr(time);
adodataset2.EnableControls;
adoquery1.UpdateBatch(arall); end;
什么这么高,我们是否可以利用呢?这些天我最大感触是项目和学习是不一样的,
学习的时候也许只要有解决方案就可以,而项目更多要考虑效率等其他一些客观问题。
au_id au_lname au_fname phone address city state zip contract
刚好也是9个field.而且我是在333中测试的,如果机器配置好速度应该更快.
原程序:
edit2.Text:=datetimetostr(time);
adodataset2.EnableControls;
adoquery1.UpdateBatch(arall);
后程序:
adodataset2.EnableControls;
adoquery1.UpdateBatch(arall);
edit2.Text:=datetimetostr(time);因为整个完成在UpdateBatch的时候非常耗时,您不能把这部分放到计时之外。
再看了一遍需求.
==================================================================
但用户要求对这个数据集进行查询,我不会对数据集使用SQL
==================================================================
我提出解决方案,不知是否可行:
1:客户端用户进行查询的时候把查询条件回传到服务器端.在服务器端进行查询,只把符合条件的记录返回给客户端.
2:如果仍然使用将大数据包传给客户的方法,不必把数据写到access中去.在内存中进行过滤也能达到查询的效果.而且可做到无论指定的是哪一个数据集的哪一列,(不需要在本地建立对应的access库.)都可以进行查询.
===================================================================
http://netroom.hbu.edu.cn/personal/mudeen/quickcopy.exe
==================================================================
这是新的测试版,呵呵.还有一些bug,不过对于普通查询已经够用了.
=================================================================
Try It
backup database to disk='d:\abc.bak' with replace
我建议你在打开SQL事件探查器,然后用SQL Server 2000的DTS向导,将SQL Server中的数据导入Access 2000导入完成后,逐条copy SQL事件探查器中记录的SQl执行语句。经过整理后,就可由用户自己调用这些SQL代码。
很多SQL的功能都能用这种办法实现。
select * from SqlTable where LastChangeTime>上次取得数据时间
BDE呀,真是让人又爱又恨.........
不知道有没有Ado下面的类似batchmove的控件.
在SQL server中建立连接服务器这样很快的!
但是好像要标准服务器板以上才支持!
。
它使用批量移动数据的方法,容易停止响应.
不像自己使用循环时可以用application.ProcessMessages来让程序响应其它操作.
下面的这段代码(在内存中为数据集增加10000条记录)执行时间要30多秒
procedure TForm1.BitBtn2Click(Sender: TObject);
var
aTimeS,aTimeE:double;
begin
if not AdoDataSet1.Active then AdoDataSet1.Active :=True;
ClientDataSet1.DisableControls;
ClientDataSet1.First;
aTimeS:=GetTickCount();
while not ClientDataSet1.Eof do
begin
AdoDataSet1.Insert;
AdoDataSet1.FieldByName('Field1').AsString:=ClientDataSet1.FieldByName('Field1').AsString;
AdoDataSet1.FieldByName('Field2').AsString:=ClientDataSet1.FieldByName('Field2').AsString;
AdoDataSet1.FieldByName('Field3').AsString:=ClientDataSet1.FieldByName('Field3').AsString;
AdoDataSet1.FieldByName('Field4').AsString:=ClientDataSet1.FieldByName('Field4').AsString;
AdoDataSet1.FieldByName('Field5').AsString:=ClientDataSet1.FieldByName('Field5').AsString;
AdoDataSet1.FieldByName('Field6').AsString:=ClientDataSet1.FieldByName('Field6').AsString;
AdoDataSet1.FieldByName('Field7').AsString:=ClientDataSet1.FieldByName('Field7').AsString;
AdoDataSet1.FieldByName('Field8').AsString:=ClientDataSet1.FieldByName('Field8').AsString;
AdoDataSet1.FieldByName('Field9').AsString:=ClientDataSet1.FieldByName('Field9').AsString;
AdoDataSet1.Post;
ClientDataSet1.Next;
end;
ATimeE:=GetTickCount();
Label1.Caption :=FloatToStr((ATimeE-aTimeS)/1000);
end;
最后的统计时间是37.354而下面这几行代码只是调用UpdateBatch将数据存盘,竟然要10多分钟的时间
procedure TForm1.BitBtn3Click(Sender: TObject);
var
ATimeS,ATimeE:double;
begin
ATimeS:=GetTickCount();
AdoDataSet1.UpdateBatch(arAll);
ATimeE:=GetTickCount();
Label2.Caption :=FloatToStr((ATimeE-aTimeS)/1000);
end;
统计的结果是598.912大家看看是什么原因,只是一个UpdateBatch啊,竟然要这么长时间
===================================================================
呵呵,你的数据都保存在内存或者虚拟内存中,导致存盘时能够使用的内存不足.
==================================================================
以上纯属猜测
应该不是内存不足的问题,我曾试过每1000条存一次,效率也差不多
你说到的数据集也可以在服务器端查询好了再返回,真需要返回所有数据,你就只好将数据全部导入本地(无论用什么统一格式都可以),时而加以标志做比较有无数据更新,无则在本地查询,有则把服务器端的带有修改标志的数据导回本地,这我想应该不成问题了吧。(而导的过程都在服务器端进行,传输的数据量不大,哪么无论网速与用户都不该有问题)OK,做项目是需要实践与方案分析,CSDN讨论是个好地方。
我是业余的,上班做网管。可以联系:QQ:4264362
mailto: [email protected]
很关心你的问题。我在ACCESS之间倒数据5000条(有备注字段),花费了我1个多小时呀!(共155M)我猜测,你的10000条数据,数据量多大?你跟用户这样说:你在WINDOWS平台上,拷贝一个这么大的文件,需要多长时间?更何况数据库呢!还有一点提醒:ACCESS数据库第一次连接时间很长,以后,你即使关掉连接了,再建立连接也是很快的。
很简单,一个是在内存中操作
一个是在硬盘中操作
这个速度,你可以想象的。
咱们能不能看一下Batchmove的代码,然后自己写一个TADOBatchmove.我真觉得这玩艺好用,不过可惜ADO不能用!
还有就是想问一下,您为什么用socket将数据传到本地,难道就是为了效率(这样效率会好多少?),用ADO的连结属性不行吗?用socket传过来后,还要很多麻烦的处理?您将传过来的数据直接就显示在DBGrid中吗?没有数据集组件怎么用Bacthmove?
您说的容易.
batchmove的源码很容易看到.呵呵,但是实现的机制是针对BDE的........
似乎不那么好改的.
您知道李颖大侠写过的那个.....dbbackup的控件吗?也是针对BDE的,但是要改写成ado的太难了..所以他说'希望能够在他的有生之年能够写出来'......
服务器端:取数据,压缩打包,一共300-400ms
传送:20-30s
写硬盘: 20-30s
如果是用连接做,恐怕查一次就要差不多这么长时间吧。但我这样说是估计,没有试验依据,我没有用连接试过,明天试试。
要用batchmove简单啊,你用个datasource转一下就行,就能用到ado中了。liuwl,我的错,确实csdn上不少问题都不是弱智问题。
一个10.4m的access数据库原来用压缩软件可以压到不大于600K的呢.
既然如此,为何不在服务器端直接把sql server 端把数据导入到access中去,然后压缩access数据库,把access数据库传输到客户端,客户端调用解压缩工具解压,然后连接到该access数据库.如此一来,在服务器端只需做少量的工作:
导出到access->压缩->传输
客户端的工作;接收->解压,然后就能查询了.这样做的话优点是不要在客户端导入数据,不要在客户端分发BDE,但是缺点是需要配合第三方的压缩工具进行操作.
至于导出到access中,如果在服务器端的话,因为不是实时响应请求,对速度要求不会太高.如果客户是每小时要求更新一次数据的话,只需在这个小时内做一次压缩就行了.如果要注重效率,也很简单,SQL sverver是可以提供了语句导出到ole db数据源中的.不知道这种方法是否满足要求..........
呵呵,要考试了,不写代码了.不过我觉得这样做肯定比用循环有效率.比分发BDE要少很多维护之苦.
您下载这个东东试一下,看一下解压缩之后是否有10.5m
压缩包大小是262k,里面有个authors表,它大概有60000条记录........
http://netroom.hbu.edu.cn/personal/mudeen/dbdemos.zip