如果aCDS在结果数据集中无法找到需要的数据,它便会再把查寻的工作交还给sqlcdsTest使用一般的Locate方法来查寻。

图4-25 使用CloneCursor方法查寻数据的结果
使用CloneCursor方法可以让开发人员巧妙地避免下载所有数据的负荷,但是CloneCursor也无法避免需要下载所有数据的情形:那就是当要查寻的数据并不存在于结果数据集中时。当这种情形发生时,使用CloneCursor方法反而比直接使用TClientDataSet/TSimpleDataSet的Locate方法来得缓慢。
要解决这个问题,让我们使用其他的技巧来克服。
使用SQL语句查寻数据
在上一小节中知道CloneCursor也无法避免TClientDataSet/TSimpleDataSet下载所有数据的情形,因此我们终究是要想方设法避免这种情形发生的可能,才能够保证在大部分的时候,也许是99.99%的情况下大幅增加查寻数据的效率。
先想想CloneCursor方法在什么时候仍然需要下载所有的数据?那就是当欲查寻的数据不存在于结果数据集之中时,那么如果我们能够在这种情形发生时,直接从数据来源中取得要查寻的这笔单一的数据,然后把它加入到TClientDataSet/TSimpleDataSet的Data特性之中,那么不就可以解决这个问题了吗?这的确是一个非常好的点子,因为同时使用CloneCursor和这种技巧,的确可以在99.99%以上的情形中大幅增加执行效率。现在看看如何实现这种功能。
范例应用程序主窗体中的Smart Locate II按钮便使用了如下的程序代码来查寻数据:
procedure TfrmFindData.btnSmartLocate2Click(Sender: TObject);
var
aCDS : TClientDataSet;
begin
aCDS := TClientDataSet.Create(Self);
try
GetStartTime;
aCDS.CloneCursor(dmFindData.sqlcdsTest, True);
if aCDS.Locate('ID', edtID.Text, [loCaseInsensitive, loPartialKey]) then
dmFindData.sqlcdsTest.MoveBy(aCDS.RecNo - dmFindData.sqlcdsTest.RecNo)
else
begin
dmFindData.sqlcdsTemp.Active := False;
try
dmFindData.sqlcdsTemp.Params.ParamByName('ID1').Value := edtID.Text;
dmFindData.sqlcdsTemp.Active := True;
if (dmFindData.sqlcdsTemp.RecordCount > 0) then
begin
dmFindData.sqlcdsTest.AppendData(dmFindData.sqlcdsTemp.Data, False);
dmFindData.sqlcdsTest.MoveBy(dmFindData.sqlcdsTest.RecordCount -
dmFindData.sqlcdsTest.RecNo)
end;
finally
dmFindData.sqlcdsTemp.Active := False;
end;
end;
GetEndTime;
AppMsg('Locate', GetRunTime);
edtTime3.Text := FloatToStr((GetRunTime) / 1000.0);
edtRecordCount.Text := IntToStr(dmFindData.sqlcdsTest.RecordCount);
finally
aCDS.Free;
end;
end;
上面的程序代码首先使用前面介绍的CloneCursor方法在结果数据集中查寻数据,但是当CloneCursor无法在结果数据集中找到欲查寻的数据时,它就使用另外一个TSimpleDataSet控件,直接借助SQL语句从后端的数据来源查寻这笔数据,如果找到的话,就调用原先TSimpleDataSet的AppendData方法把找到的这笔数据加入其中,并且把cursor移动到这笔数据之上。
图4-26便是使用这个技巧查寻数据的结果,从图中可以看到由于查寻的是A025800680这笔数据,它使用CloneCursor的技巧来找到这笔数据,速度是非常快的。稍后我们会查寻其他不在目前结果数据集中的数据,看看结果会如何。

图4-26 使用CloneCursor方法和SQL语句查寻数据的结果
在我们继续讨论之前,先看看只是简单地使用CloneCursor方法就可以增加数百倍的效率执行,如图4-27所示。

图4-27 比较三种查寻数据方法的执行效率
现在让我们继续查寻一些目前不存在于结果数据集之中的数据,看看不同的查寻方式是否有任何的差异。
查寻尾端数据
现在让我们查寻位于数据表中后端的数据,由于这笔数据现在不在结果数据集中,因此TSimpleDataSet必须从后端的数据来源中取得数据。那么直接使用Locate、 CloneCursor或是CloneCursor加SQL语句会有什么差别呢?
图4-28再次执行范例应用程序,并且查寻W145812312这笔记录的结果,直接使用Locate的执行结果和前面查寻已经存在于结果数据集中的数据几乎没有什么不一样,因此直接使用Locate、Lookup和Filter等方法查寻数据时,不管要查寻的数据已经存在于结果数据集中,或是还在后端数据来源中,所花的时间几乎都一样,非常稳定。

图4-28 使用Locate方法查寻后端数据的结果
如果使用CloneCursor方法查寻不存在于结果数据集中的数据,那么结果如图4-29所示,比直接使用Locate等方法差了许多。之所以执行效率下降是因为由于现在这笔数据在结果数据集中,因此前面讨论的CloneCursor仍然会再使用Locate方法查寻数据,至少需要花上和直接使用Locate方法一样的时间。不过由于此时TSimpleDataSet需要维护两个Cursor,因此速度会更缓慢,这就是为什么需要花上5秒多的时间。

图4-29 使用CloneCursor方法查寻后端数据的结果
请注意,这时CloneCursor方法也已经把后端的数据来源中所有的数据下载到客户端,并没有节省任何的数据笔数。






