最后让我们使用Smart Locate II的方法来查寻数据,由于此时这笔数据不在结果数据集中,因此Smart Locate II会使用SQL语句直接在后端数据来源中查寻数据,再把查寻的数据加入客户端的TSimpleDataSet中。图4-30是查寻W145812312这笔记录的结果。
请注意,使用这种方法查寻数据时,它的执行效率仍然是最好的,比刚才前两种方法快了数百倍。同时这种方法会让结果数据集中维持最少的数据。例如前面的两种方法都会下载所有的数据,但是这种方法却只会下载一笔数据,此时结果数据集中只有11笔数据,而前面的两种方法却下载了10 000笔数据,之间的差异是很大的。如果在一个网络环境中,客户端有许多的用户同时执行系统,那么这种方法可以大幅度降低网络的负荷。

图4-30 使用CloneCursor加SQL语句方法查寻后端数据的结果
图4-31是使用三种方法查寻不在结果数据集中数据的结果,请和前面的图形比较一下,我们会发现直接使用Locate等方法需要花的时间是一样的,非常稳定。CloneCursor方法则大幅地降低了执行效率。至于CloneCursor加SQL语句仍然是最快速的,而且会下载最少的数据量。

图4-31 三种方法查寻后端数据的结果
使用CloneCursor加SQL语句方法虽然是最快速的,但是这种方法也有副作用。那就是如果稍后用户一直存取随后的数据,那么当TClientDataSet/TSimpleDataSet存取到后端包含刚才直接使用SQL语句的PacketRecords时,TClientDataSet/TSimpleDataSet控件中便会包含重复的数据。不过这个情形在数据量大的应用中并不会经常发生,仍然值得开发人员使用。即使会发生这种情形,我们仍然有非常有效的方法来克服,稍后会继续说明。
使用TClientDataSet的Data特性来查寻数据
到这里为止,范例应用程序的Smart Locate方法可能会让开发人员陷入两难的境界中,因为CloneCursor方法虽然可以快速地在结果数据集中找到用户欲查寻的数据,但是当要查寻不在结果数据集中的数据时,却需要花上更多的时间。那么到底有没有更好的方法可以让查寻结果数据集的数据非常快速,查寻不在结果数据集的数据时能够与提供和直接使用Locate等方法拥有类似的效率,而且也没有使用CloneCursor加SQL语句的副作用呢?
还是有的,那就是直接动TClientDataSet/TSimpleDataSet控件的Data特性值的脑筋。当程序欲查寻数据时,我们可以先把原先TClientDataSet/TSimpleDataSet控件的Data特性值拷贝给另外新的一个TClientDataSet/TSimpleDataSet控件的Data特性值,再于新的TClientDataSet/TSimpleDataSet控件中使用Locate等方法查寻数据,这样可以切断和后端数据来源的连接,避免下载所有的数据。然后再于新的TClientDataSet/TSimpleDataSet控件中查寻数据,这样可以快速地在结果数据集中查寻数据。如果没有找到的话,就再要求原先的TClientDataSet/TSimpleDataSet控件于后端的数据来源中查寻数据。因此我们再加入另外一个Smart Locate I的按钮,并且使用如下的程序代码来查寻数据:
procedure TfrmFindData.btnSmartLocate1Click(Sender: TObject);
var
aCDS : TClientDataSet;
begin
aCDS := TClientDataSet.Create(Self);
GetStartTime;
// aCDS.CloneCursor(dmFindData.sqlcdsTest, True);
aCDS.Data := dmFindData.sqlcdsTest.Data;
if aCDS.Locate('ID', edtID.Text, [loCaseInsensitive, loPartialKey]) then
dmFindData.sqlcdsTest.MoveBy(aCDS.RecNo - dmFindData.sqlcdsTest.RecNo)
else
begin
aCDS.Free;
dmFindData.sqlcdsTest.Locate('ID', edtID.Text, [loCaseInsensitive,
loPartialKey]);
end;
GetEndTime;
AppMsg('Locate', GetRunTime);
edtTime2.Text := FloatToStr((GetRunTime) / 1000.0);
edtRecordCount.Text := IntToStr(dmFindData.sqlcdsTest.RecordCount);
end;
上面的程序代码即是把原始数据集中的数据(Data特性)指定给另外一个暂时的TClientDataSet-aCDS,再对aCDS进行查寻数据的工作。如果在aCDS中找到了数据,便让数据集sqlcdsTest的目前记录指针移动到此数据之上。如果在aCDS中没有找到用户欲查寻的数据,这代表欲查寻的数据尚未存取到客户端,那么就直接让数据集sqlcdsTest的Locate来进行查寻。
现在让我们使用另外一个拥有更多数据的数据表来测试,这个测试数据表包含了50 000笔的数据,以便了解拷贝数据到另外一个TClientDataSet/TSimpleDataSet是否需要花上大量的时间,只有在这个操作需要少量时间的前提下才值得我们使用。
图4-32至图4-35是分别查寻已经存在于结果数据集中的数据,以及查寻还不存在于结果数据集中数据的结果。

图4-32 直接使用Locate查寻数据

图4-33 借助TClientDataSet/TSimpleDataSet的Data特性值查寻数据

图4-34 直接使用Locate查寻不在结果数据集中的数据

图4-35 借助TClientDataSet/TSimpleDataSet的Data特性查寻数据
图4-36是借助Data特性值查寻数据的比较图,从图中可以看到使用Data特性值来查寻数据的确可以获得良好的执行效率。当查寻已经存在于结果数据集中的数据时,它可以提供数百倍优于直接使用Locate方法的效率。而查寻不存在于结果数据集中的数据时,它可以提供和直接使用Locate方法一样的执行效率,而没有明显的差异。这个技巧融合了CloneCursor的优点,而又避免了CloneCursor+SQL的缺点。

图4-36 三种查寻数据方法的结果比较
从这个测试中我们可以推知一个重要的DataSnap/dbExpress的执行行为,那就是当我们拷贝一个TClientDataSet/TSimpleDataSet的Data特性值时,DataSnap/dbExpress似乎只是像COM/DCOM一样增加了原先Data特性值的引用计数值,而没有真正地在内存中拷贝大量的数据,因此这个查寻技巧才能够在查寻不存在于结果数据集中的数据时,提供和直接使用Locate方法一样的效率。也是因为这种特性,才值得我们使用这个技巧。
表4-9列出了四种查寻数据方法的优缺点,开发人员可以根据应用程序的需要选择适当的查寻方法。
表4-9
|
查寻方式 |
缺点 |
优点 |
|
Locate |
会从数据来源中下载所有的数据,如果数据表中包含大量的数据,那么执行效率会很缓慢,而且容易造成客户端的当机 |
查寻数据的执行效率保持稳定的结果,而不管要查寻的数据是否已经存在于结果数据集中,而且没有其他的副作用 |
|
使用CloneCursor |
如果欲查寻的数据不在结果数据集中,那么仍然会下载数据表中所有的数据,而且表现的比直接使用Locate等方法还缓慢 |
如果欲查寻的数据已经存在于结果数据集中,那么它可以避免下载所有的数据,并且能够快速地找到查寻的数据 |
|
使用CloneCursor加SQL语句加AppendData |
可能会发生重复数据的副作用 |
提供最快的查寻效率,不管数据是否在结果数据集中,或是后端数据来源中。同时下载的数据量最少,网络的负荷最轻 |
|
使用拷贝数据 |
程序必须拷贝一些额外的数据 |
可以提供比直接使用Locate等方法更好的查寻效率,同时没有CloneCursor方法的缺点,也没有CloneCursor加SQL语句的副作用 |
避免CloneCursor+SQL语句会产生重复数据的情形
在前面讨论CloneCursor+SQL的查寻技巧中,我们知道这种方式虽然是最迅速的,但是却有可能产生数据重复的情形,这似乎有一点美中不足。事实上要解决这个问题也不困难,只要我们再结合一些小技巧就又可以克服了。
首先使用一个TClientDataSet拷贝原先TClientDataSet/TSimpleDataSet的Data特性值,接着当原先的TClientDataSet/TSimpleDataSet存取每一个随后的PacketRecords时,先一一地在拷贝的TClientDataSet中使用Locate检查PacketRecords中的数据是否已经存在,如果在的话,那么就先删除PacketRecords中的这笔数据。当所有PacketRecords中的数据都检查完毕之后,再使用AppendData把数据加入到原先的TClientDataSet/TSimpleDataSet,这样就不会产生重复数据的问题了,如果你不要把PacketRecords的特性值设太大,例如只设10笔,那么这个检查数据重复的负荷成本将会非常的小,因此不会影响执行的效率。
从本小节的讨论中可以知道,开发人员在了解了dbExpress的工作原理,再配合一些程序技巧就可以让查寻数据的速度大幅提升。不过本小节讨论的增加查寻效率技巧仍然需要开发人员根据自己数据库应用系统的需要使用适当的技术,没有一种技巧是可以在各种数据情形中都能够大幅增加执行效率的。除了查寻数据的执行效率之外,在稍后的章节中将会进一步地讨论如何有效地处理变更的数据。






