数据分页问题(主要解决效率问题),请有经验的高手指点。 yysun老师?(100分)

R

Rocklee

Unregistered / Unconfirmed
GUEST, unregistred user!
我的代码如下 :
Procedure RefreshData; //重新打开数据集
begin
adodataset.sql.add('select trx_trxdt,trx_namecd,trx_nameno,trx_work
from paytrx where trx_trxdt>=''08/01/2001' and trx_trxdt<=''09/01/2001''');
adodataset.open;
adodataset.recordset.pagesize=15; //一页的记录数
f_Pages:=adodataset.recordset.pagecount; //结果有多少页
DoShowData(1);
end;
Procedure DoNextPage; //显示下一页
begin
Inc(PageIndex);
if PageIndex>adbquery.recordset.PageCount then
PageIndex:=adbquery.recordset.PageCount;
DoShowData(PageIndex);
end;
Procedure DoPrePage; //显示上一页
begin
Dec(PageIndex);
if PageIndex<1 then
PageIndex:=1;
DoShowData(PageIndex);
end;

procedure DoShowData(pgIdx:integer); //显示指定页数的内容
var i:integer;
begin
with adbdataset do begin
adbdataset.recordset.absolutpage:=pgIdx;
for i:=1 to recordset.pagesize do begin
memo1.lines.add(fieldbyname('trx_trxdt').asstring+ ' '+
fieldbyname('trx_namecd').asstring+' '+ ....);
next;
if adbdataset.eof then break;
end;
end;
end;
代码完全无错,运行也没有问题,只是效率不如我想像的快,一样让我等,好像和没有用分页差不多。
各位想用分页技术的大哥们无非也想获得高的效率(减少网络流量)。
但好像从上面的代码中看不出效果来。
如果我将 Recordset.size=5这句放在Open之前,则会死得很难看。
还有一个游标类型(可以选在Server/Client),我改过,都无什么差别。
希望在这方面有所发现的大哥们谈论谈论。
我相信很多同行都会遇到和我一样问题,就是当用户按条件拉回数据并且进行修改时,
假如拉回来的数据有一万或数十万的时候,现上面所说的尴尬问题.

yysun老师,请指教。
(另:多谢yysun老师给我邮来msxml)
 
试试将ado设为异步执行
 
用query+updatasql实现就可以了。
 
应该是用MaxRecord属性来控制返回的记录数的,然后再根据记录的内容,计算前后的
页数,在显示页的时候,根据相关的字段进行显示的控制。

另外用ADOQuery好一点。
 
>>假如拉回来的数据有一万或数十万的时候
如果是那样,分页也没用,这是SQL执行效率的问题
DFW上有篇文章<如何让你的SQL运行得更快>,就是提到这个问题
你查查罢(文章很长,在这贴出来我怕被人打)

其实浏览显示数据,往往是慢在“显示”上
分页显示我也做过
我的方法是先一次把需要的数据读到数据集中
然后控制它显示哪部分的数据
例子:(我用的是dxTreeList,不是数据感知控件,类似stringgrid)
procedure TForm2.Button20Click(Sender: TObject);
var
p,c : integer;
begin
ADODataSet1.Close;
ADODataSet1.Open;

c := ADODataSet1.RecordCount;

if (c mod 10 = 0) then
begin
p := trunc(c/10);
end
else
p := trunc(c/10)+1;

Label3.Caption := IntToStr(p);

ShowPage(1);//显示第1页的数据

end;

//显示第几页的数据函数
procedure TForm2.ShowPage(Index: Integer);
var
b,e : integer;
i: integer;
dx: tdxtreelistnode;
begin
//
b := (Index-1)*10+1;
e := Index*10;

dxTreeList2.BeginUpdate;
dxTreeList2.ClearNodes;
dxTreeList2.EndUpdate;

ADODataSet1.First;
ADODataSet1.MoveBy((Index-1)*10);

for i := 1 to 10 do
begin
dx := dxTreeList2.Add;
dx.Values[0] := ADODataSet1.RecNo;
dx.Values[1] := ADODataSet1['project_id'];

ADODataSet1.Next;
if ADODataSet1.Eof then break;
end;
end;
 
我也知道,所以我就想用什么方法可以做到分页在服务端进行而不是在客户端?
单纯用SQL+ado可以实现吗(我不希望用MIDAS的方法)?
 
用MaxRecord属性来控制返回的记录数的,然后再根据记录的内容,计算前后的
页数,在显示页的时候,根据相关的字段(例如ID等)进行显示的控制。

这样不可以吗?
 
认为ado的pagesize可以控制服务器返回数据量的想法是个误解.
ado的pagesize是用来方便定位数据记录的.(这个属性在做网页分页显示时特别有用)
请注意:
adodataset.open; //数据已从服务器读回来了
adodataset.recordset.pagesize=15; //再分页方便定位记录.
 
zhanggeye说得对,这个分页是在客户端进行的,因此这样分页只是控制,实际上还是选出了
所有的纪录。
要控制流量,只能从服务端运行,本人写过一个存储过程进行分页操作,大致代码如下:
SET @sSQL = ''
If (@topcount IS NULL)
SET @topcount = 1000000

IF @counts <= @topcount
BEGIN
SET @sSQL = 'select top '+ CONVERT(VARCHAR(8), @counts) +' * from Visitor where ' + @vt_id_sSQL + ' and panel_id = 0 and v_checked = ' + CONVERT(VARCHAR(2),@v_checked) + @searchSQL + ' order by V_ID DESC'
END
Else
BEGIN
IF @page < (@counts/@topcount)/2
BEGIN
IF @page < 1 SET @page = 1
IF @page = 1
SET @sSQL = 'select top '+ CONVERT(VARCHAR(8), @topcount * @page) +' * from Visitor where ' + @vt_id_sSQL + ' and panel_id = 0 and v_checked = ' + CONVERT(VARCHAR(2),@v_checked) + @searchSQL + ' order by V_ID DESC'
ELSE
BEGIN
SET @sSQL = 'select top '+ CONVERT(VARCHAR(8),@topcount * @page) +' v_id from Visitor where ' + @vt_id_sSQL + ' and panel_id = 0 and v_checked = ' + CONVERT(VARCHAR(2),@v_checked) + @searchSQL + ' order by V_ID DESC'
SET @sSQL = 'select top '+ CONVERT(VARCHAR(8),@topcount) +' v_id from Visitor where v_id in ('+ @sSQL +') order by v_id ASC'
SET @sSQL = 'select top '+ CONVERT(VARCHAR(8),@topcount) +' * from Visitor where v_id in ('+ @sSQL +') order by v_id DESC'
END

END
ELSE
BEGIN
IF @page > (@counts/@topcount + 1) SET @page = @counts/@topcount + 1

SET @sSQL = 'select top '+ CONVERT(VARCHAR(8), @counts - @topcount * (@page-1)) +' v_id from Visitor where ' + @vt_id_sSQL + ' and panel_id = 0 and v_checked = ' + CONVERT(VARCHAR(2),@v_checked) + @searchSQL + ' order by V_ID ASC'
SET @sSQL = 'select top '+ CONVERT(VARCHAR(8),@topcount) +' * from Visitor where v_id in ('+ @sSQL +') order by v_id DESC'
END

END
 
在服务器端就分段取数据,再传给客户端(用于有唯一键值时):
如本来根据要求服务端要取出Select * From Table Where field=1,假如符合条件的共有
四十万条,即使客户端分段下载,服务端也需全部打开记录,当然慢得够呛。
那么,我们合不减轻服务端负担,在服务端也分段下载。
在SQL Server中,用Select Top 30 * From Table where filed=1 and iID>n order by iID,
第一次,客户端送给服务端的参数n为0,既得到全部的符合条件的头30条记录。当客户端
下拉滚动条到最后一条记录时,表示需求下面的记录,于是用另一个ClientDataSet2去找
数据,此时用的语句为:Select Top 30 * From where field=1 and iID> lastiID order by iID,
其中LastiID为ClientDataSet1中的最后一条记录,然后用AppandData加到ClientDataSet1中。
这样,客户端是浏览多少就向服务端要求多少,而服务端则也是客户端要求什么就只收索相
应30条,两边负担都不大。而且,据我实验,Sql Server 执行 Select Top 30 * From Table
的速度还是比较快的,基本感觉不出来。
其他数据库同样可以用同样的方法。
 
关于ado效率的问题,我从bde转过来时也很困惑,
看过李维的书后才有初步了解,当你一次查询记录很多时,
任何体系都不可能会有太好的表现,所以要从查询上先控制好返回的记录数量。
取回记录多时最最主要的是使用servercursor.
我打开一个5万记录表,使用clientcursor是90S,而用servercursor是1.2S,
而且我觉得cachesize是1000时确有比较好的表现.
 
guqs的方法不错呀,学习
 
学习学习
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
顶部