2.1.9 控制数据存取笔数——PacketRecords属性
TSimpleDataSet/TClientDataSet的PacketRecords属性已经在前面介绍过了,这个属性对于整个dbExpress程序设计都有重大的影响,因此读者必须了解并且掌握这个属性。PacketRecords的默认值是-1,这代表当TSimpleDataSet/TClientDataSet打开后,它会尽可能地把数据源中的数据一次存取到客户端。对于拥有少量数据的数据源来说,这可能是很好的选择,但是对于拥有大量数据的数据源来说,这却是不好的设定。一般的情形中开发人员可以调整TSimpleDataSet/TClientDataSet的PacketRecords属性值为10到100之间,一次只存取应用程序需要的数据。这样可以让应用程序的反应时间良好,也可以节省客户端的资源。请记住一定要在真正需要一次存取所有的数据时才设定PacketRecords为-1。
现在让我们看一个小范例来说明PacketRecords属性。首先在Delphi中建立一个新的应用程序,再建立一个新的数据模块,然后在数据模块中放入一个TSQLConnection连接到范例数据库D2006HDBP,放入一个TSQLDataSet控件,设定它的CommandText为select * from PERFTEST,再放入一个TDataSetProvider控件,连接到TSQLDataSet,最后再放入一个TClientDataSet控件,设定它的ProviderName为TDataSetProvider控件的名称。在PERFTEST数据表中拥有1 000笔的数据,此时数据模块如图2-17所示。

图2-17 范例应用程序的数据模块
到主窗体中加入TDataSource、TDBNavigator、TDBGrid、TStatusBar和一个TButton、TSpinEdit、TListBox控件。设定数据感知控件连接到数据模块中的cdsPERFTEST(见图2-18)。
在主窗体的【设定PacketRecords】按钮的OnClick事件处理函数中,会根据用户在TSpinEdit中设定的数值来设定cdsPERFTEST的PacketRecords属性值。下面就是这个按钮的OnClick事件程序代码:
procedure TfrmMain.Button1Click(Sender: TObject);
begin
dmDemo.cdsPERFTEST.Active := False;
LogStartTime;
dmDemo.cdsPERFTEST.PacketRecords := sedtPacketRecords.Value;
dmDemo.cdsPERFTEST.Active := True;
LogEndTime;
LogMsg(sedtPacketRecords.Value, GetRunTime);
end;

图2-18 范例应用程序的主窗体
上面的程序代码先关闭cdsPERFTEST控件,再设定它的PacketRecords属性值,最后再打开cdsPERFTEST,并且把这整个过程花费的时间显示在主窗体的TListBox之中。
此外在范例应用程序执行时,我们也想要知道dbExpress目前在客户端应用程序中到底从数据源取得了多少笔数据。要如此做,我们可以存取TSimpleDataSet/TClientDataSet控件的RecordCount属性值来得知目前在Data属性值中的数据笔数。
除了知道如何存取目前客户端的数据笔数之外,我们也必须决定在什么地方比较适合存取数据笔数的信息。其中第一个地方是当TSimpleDataSet/TClientDataSet被打开的时候,那就是它的AfterOpen事件。另外一个地方是当TSimpleDataSet/TClientDataSet需要从数据源存取下一个数据封包时,那就是它的AfterGetRecords事件。因此我们只需要在这两个事件中显示TSimpleDataSet/TClientDataSet的RecordCount属性值,便可以知道目前在客户端被存取的数据笔数。下面就是本范例应用程序在这两个地方显示RecordCount属性值的程序代码:
procedure TdmDemo.scdsDemoAfterOpen(DataSet: TDataSet);
begin
Form1.ShowRecordCount(scdsDemo.RecordCount);
end;
procedure TdmDemo.scdsDemoAfterGetRecords(Sender: TObject;
var OwnerData: OleVariant);
begin
if (scdsDemo.Active) then
Form1.ShowRecordCount(scdsDemo.RecordCount);
end;
现在编译并且执行范例应用程序。图2-19便是使用PacketRecords为10打开TSimpleDataSet的画面。从主窗体下方的TStausBar3中可以看到目前客户端果然只存取了10笔数据。

图2-19 范例应用程序使用PacketRecords为10的执行画面
现在如果我们点击TDBNavigator不断地向下浏览数据,便会发现当浏览第11笔数据时,TSimpleDataSet/TClientDataSet会自动地再向数据源取得下一个数据封包,此时TStatusBar也会显示数据笔数已经成为20笔了。所以证明了TSimpleDataSet/ TClientDataSet一次是以PacketRecords指定的数目从数据源存取数据(见图2-20)。
至于图2-21则是使用PacketRecords为100向数据源存取数据,不管PacketRecords值为何,TSimpleDataSet/TClientDataSet的执行行为都是一样的,但是我们发现范例应用程序使用100作为PacketRecords值似乎比10来得快,读者可以自行试着调整PacketRecords值,看看不同的PacketRecords值会有什么样的执行结果。

图2-20 范例应用程序会自动存取下一个数据封包

图2-21 范例应用程序使用PacketRecords为100的执行画面
这个范例显示了TSimpleDataSet/TClientDataSet的PacketRecords可以控制一次从数据源中取得数据的笔数,让开发人员能够控制客户端应用程序需要的数据。另外我们也可以发现不同的PacketRecords属性值会对应用程序产生不同的反应时间,开发人员可以根据自己的应用来设定PacketRecords属性值,一般来说,如果PacketRecords属性值不是设定成-1,那么10到1 000之间是比较好的设定。如果客户端使用的人数多时,那么开发人员可能需要减少PacketRecords属性值为10到100之间。
这本高效数据库程序设计篇其实在Delphi 6时就已经开始撰写,不过笔者到了Delphi 7才推出本书。在笔者把Delphi 6的程序更改成Delphi 7时发现Delphi 7的dbExpress的执行效率比Delphi 6时又快了很多,许多执行数字比Delphi 6时快了10%~30%,令人非常惊讶又兴奋,看来Borland仍然在不断地改善dbExpress的性能,也许在读者阅读本书时dbExpress又有了进步。在Delphi 2006中dbExpress 3.0的执行效率再次提升,比Delphi 7的dbExpress 2.0快了5%~10%的速度,而且支持了MS SQL Server 2005。






