不知道微软还有没有脸,用VB的ADO后期绑定测试了一下相同的流程,竟然要一个多小时! 如何提高ADO简单过程(Edit…Post Next)的效率(500分)

  • 主题发起人 主题发起人 jsxjd
  • 开始时间 开始时间
J

jsxjd

Unregistered / Unconfirmed
GUEST, unregistred user!
不知道微软还有没有脸,用VB的ADO后期绑定测试了一下相同的流程,竟然要一个多小时! 如何提高ADO简单过程(Edit…Post Next)的效率(500分) 附:一个好的表结构和树 (0分)<br />如何提高ADO简单过程(Edit…Post Next)的效率

一般情况下,通过执行SQL都可以取得较高的效率,基本上是“瞬间”完成。但有时记录的值必须由前面多条记录的值动态计算得到,这时无法通过简单的SQL来实现,必须进行逐条扫描更新。
在实际测试时发现,用ADO连接VF的DBF文件,即使执行下面的简单过程,效率是“无法忍受”的。

PIII550,DBF文件一万条记录:
能使以下简单过程在5秒内完成,500分;
10秒内,300分;
1分钟内,200分;
能有效改善性能也给分。

procedure TForm1.Button2Click(Sender: TObject);
var
n:dword;
begin
n:=gettickcount();
with AdoTable1 do //AdoTable 的其它属性均为默认设置
begin
ConnectionString:=getVFConnStr('d:/dbTest');
TableName:='gypcbz';
Locktype:=ltOptimistic;
active:=true;
First;
while not(eof) do
begin
Label1.caption:=inttostr(recno);
application.ProcessMessages ;
//上面两句不是实质性的,只是为了查看
edit;
fieldByName('id').Asstring:='';
post;
next;
end;
active:=false;
end;
n:=gettickcount()-n;
label1.caption:=inttostr(n);
end;



当然,要实现上面的功能用以下SQL就可以了:
Update gypcbz set id=’’

事实上,上面的过程是从下面简化来的:
function GetVFConnStr(d:string):string;
begin
Result:='Provider=MSDASQL.1;'+
'Persist Security Info=False;'+
'Extended Properties='+
'"Driver='+
'{Microsoft Visual FoxPro Driver};'+
'UID=;SourceDB='+d+
';SourceType=DBF;Exclusive=No;'+
'BackgroundFetch=Yes;Collate=Machine;'+
'Null=Yes;Deleted=Yes;";'+
'Initial Catalog='+d;
end;

function getLevel(s:string):integer;
begin
Result:=1;
if copy(s,3,6)='000000' then exit;
Result:=2;
if copy(s,4,5)='00000' then exit;
Result:=3;
if copy(s,5,4)='0000' then exit;
Result:=4;
if copy(s,7,2)='00' then exit;
Result:=5;
end;

function getNormalCode(s:string):string;
const n:array[1..5] of integer=(2,3,4,6,8);
begin
result:=Copy(s,1,n[getLevel(s)]);
end;

function getCodeLen(nn:integer):integer;
const n:array[1..5] of integer=(2,3,4,6,8);
begin
Result:=n[nn];
end;
procedure TForm1.Button1Click(Sender: TObject);
const MinLevel=5;
var
s,s1:string;
n,L,i,nL:dword;
Node:array[0..MinLevel] of TTreeNode;
begin
n:=gettickcount();
for i:=0 to MinLevel do Node:=nil;
s:=getVFConnStr('d:/dbTest');
Treeview1.items.BeginUpdate;
Treeview1.Items.Clear;
with AdoTable1 do
begin
Locktype:=ltOptimistic;
// Locktype:=ltBatchOptimistic;
ConnectionString:=s;
TableName:='gypcbz';
active:=true;
BlockReadSize:=1000;
First;
while not(eof) do
begin
Label1.caption:=inttostr(recno);
application.ProcessMessages ;
s:=FieldByName('cpdm').asstring;
L:=getLevel(s);
s1:=getNormalCode(s);
s:='['+s1+']'+
Trim(FieldByName('cpmc').asstring);
nL:=0;
for i:=L-1 downto 1 do
if Node&lt;&gt;nil then
begin
nL:=i;
break;
end;
Node[L]:=Treeview1.Items.AddChild(Node[nL],s);
for i:=L+1 to MinLevel-1 do Node:=nil;
edit;
fieldByName('id').Asstring:=s1;
if nL=0 then s1:=''
else
begin
s:=Node[nL].Text;
s1:=copy(s,pos('[',s)+1,getCodeLen(nL));
end;
fieldByName('p_id').Asstring:=s1;
post;
next;
end;
// UpdateBatch(arAll); //Locktype:=ltBatchOptimistic;时使用
active:=false;
end;
TreeView1.items.EndUpdate;
n:=gettickcount()-n;
label1.caption:=inttostr(n);
end;
 
To jsxjd
可否留下你的mail和qq
 
jsxjd见贴子 1401617

不好意思

给错了,我在开一个新贴给你200分如何?

只要你有时间关注一下该贴,我会把ID给贴过来的
 
能否帮忙看看这个帖子,帮助解决一下问题。多谢!有关COOKIE的。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1452903
 
导入sqlserver里,加上自增字段,然后再导出
 
能不能直接通过ADO的设置来提高。
如果通过其它手段,直接用 Foxpro ,瞬间即可完成。
 
这是ADO的机制限制造成的,我的做法是尽量避免这种做法,特别是超过1000以上的循环次数,
应该分解在不同的地方进行,或者放在另外的线程中在后台执行。

如果实在避免不了,以下是我的测试结果和优化建议:
PIII 1.13G, Access 数据库, 10000条记录,循环修改一个字段
建立了Primary Key,Select * from: 117秒;
建立了Primary Key,Select id,name,addr,salary from: 120秒;
没有PK,也没有索引,DisableControls:220秒;
建立了PK,没有 DisableControls: 302秒。
(奇怪的是,用select * 反而比指定字段快一点点)

优化建议: 一定要建立Primary key,更新前要 disablecontrols。
 
设置主键确实能提高效率,但上面的程序还是要运行700多秒。而且改变以下的设置没任何效果,会不会Delphi 对ADO的封装有问题。

CacheSize:=1 / 1000
Cusortype:= ctOpenForwardOnly / ctKeyset
LockType:= ltOptimistic / ltBatchOptimistic
 
这几项设置只对SQL Server影响比较明显,对本地文件型数据库几乎可以忽略。
 
没有其它的优化选项了吗?
 
查找的时候有索引就比较快,但更新的时候没有索引是最快的。
用sql语句应该是最快的,一般我们看到他这么慢通常是控件的显示比较慢。
 
CursorLocation := clUseServer;
 
self.ADOQuery1.DisableControls
self.ADOQuery1.EnableControls
我觉得有用的!!
 
我觉得你的权结构有问题!!!
我一般先添加每一级节点!!
再当客户点了结点后,再取数据,再添加树!!
这样速度就不会那么满了!!
数据越多越有优势!
 
小伙,你要试试
self.ADOQuery1.DisableControls
.........//你的NEXT,添加代码!!
self.ADOQuery1.EnableControls
我觉得有用的!!
 
你上面的TREE,好象是关于TREE存盘的!!
推荐你这样想!!
每个节点修改或新增后立即更新台后台!
给每个节点加个编号:
如 101 一级
10101 二级
10101A 三级
10101A01 四级
象传统的KEY PARENT的确很麻烦!
 
你的有道理,我的另一遍文章就是这样的,
只是我想从另一种角度生成树的时候,
想把现有的表转换一下遇到的问题。

看看我以前写的!!!!!!!!!


18. 由数据库表构造树一:好的编码和节点顺序
假设数据库表中有两个字段,分别为产品代码(CPDM)和产品名称(CPMC),代码为8位数字符型。
XX000000:前两位为大类代码,大类编码的后六位全为0;
XXY000000:第三位为中类代码,中类编码的后五位全为0;
XXXY0000:第四位为小类代码,小类编码的后四位全为0;
XXXXYY00:第五、六位为产品代码,产品编码的后六位全为0;
XXXXXXYY:最后两位为规格品代码,规格品代码的后两位一定不全为0。
大类下面可以没有中类或小类或产品,中类下可以没有小类或产品,小类下可没有产品。
所有的代码在库中按从小到大的顺序排列,所以子节点肯定在父节点后。

这样的库结构对构造树是非常有利的,一次扫描就可以了。PIII550近一万条记录不到9秒。
function getLevel(s:string):integer;
begin
Result:=1;
if copy(s,3,6)='000000' then exit;
Result:=2;
if copy(s,4,5)='00000' then exit;
Result:=3;
if copy(s,5,4)='0000' then exit;
Result:=4;
if copy(s,7,2)='00' then exit;
Result:=5;
end;

function getNormalCode(s:string):string;
const n:array[1..5] of integer=(2,3,4,6,8);
begin
result:=Copy(s,1,n[getLevel(s)]);
end;
procedure TForm1.Button1Click(Sender: TObject);
const MinLevel=5;
var
s:string;
n,L,i,nL:dword;
Node:array[0..MinLevel] of TTreeNode;
begin
n:=gettickcount();
for i:=0 to MinLevel do Node:=nil;
s:=getVFConnStr('d:/dbTest');
Treeview1.items.BeginUpdate;
Treeview1.Items.Clear;
with AdoTable1 do
begin
ConnectionString:=s;
TableName:='gypcbz';
active:=true;
First;
while not(eof) do
begin
s:=FieldByName('cpdm').asstring;
L:=getLevel(s);
s:='['+getNormalCode(s)+']'+
Trim(FieldByName('cpmc').asstring);
nL:=0;
for i:=L-1 downto 1 do
if Node&lt;&gt;nil then
begin
nL:=i;
break;
end;
Node[L]:=Treeview1.Items.AddChild(Node[nL],s);
for i:=L+1 to MinLevel-1 do Node:=nil;
next;
end;
active:=false;
end;
TreeView1.items.EndUpdate;
n:=gettickcount()-n;
label1.caption:=inttostr(n);
end;



 
哈哈,没想到你就是富得冒油的jsxjd,~~~~~ 把分拿来!!

给每个节点加个编号:
如 101 一级
10101 二级
10101A 三级
10101A01 四级
象传统的KEY PARENT的确很麻烦!
这种办法对查找很方便的!!很容易管理!!!推荐这样!!!
单纯的用KEY,PRENT 会有很麻烦!!我一般首位码的长度是固定的,后面码的长度不固定,不般
用一个特定的分隔符!!!可以任意级别!!



 
wiseinfo:
你说的方法不是和我上面的类似嘛?!可以说是一样的。
 
后退
顶部