首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 开源 FAQ 第二书店 博文视点 程序员
频道: 研发 数据库 中间件 信息化 视频 .NET Java 游戏 移动 服务: 人才 外包 培训
    图书品种:235680
       
热门搜索: ASP.NET Ajax Spring Hibernate Java

4.3.4  有效地查寻数据

在本小节中将使用一个范例来观察并且改善查寻数据的速度,并且也会观察这些不同的技术对于结果数据集中数据数量的影响。在下面的内容中你将会发现有一些技术可以大幅地改善执行效率,不过天下没有白吃的午餐,虽然这些技术可以加快执行效率,但是也会产生其他的副作用,开发人员必须根据本身的需求并结合不同的技术来达到最佳的效果。

首先让我们从最基础的地方开始,图4-23是本小节使用的范例应用程序主窗体。在这个主窗体中有LocateLookupFilter等的按钮,它们分别使用TClientDataSetLocateLookupFilter方法查寻特定的数据,而Smart LocateSmart Locate II则是稍后讨论的增加查寻效率的按钮。加下角的TEdit会显示使用各种不同的查寻方法时在结果数据集中产生的记录数量。本范例查寻的对象是一个包含一万笔数据的数据表。

4-23  查寻数据范例的主窗体

首先使用Locate来查寻数据,不过先要查寻数据是属于大量数据之中前端的数据。在本范例中TClientDataSetPacketRecords特性值是设定为10的。

使用TClientDataSetLocateLookupFilter方法查寻数据

范例应用程序主窗体中Locate按钮使用了下列的程序代码查寻范例数据表中键值字段ID,现在你应该很熟悉Locate的语法,因此就不再多说了。

procedure TfrmFindData.btnLocateClick(Sender: TObject);

begin

  GetStartTime;

  dmFindData.sqlcdsTest.Locate('ID', edtID.Text, [loCaseInsensitive,
    loPartialKey]);

  GetEndTime;

  AppMsg('Locate', GetRunTime);

  edtTime1.Text := FloatToStr((GetRunTime) / 1000.0);

  edtRecordCount.Text := IntToStr(dmFindData.sqlcdsTest.RecordCount);

end;

现在执行应用程序,在主窗体中的Locate按钮旁的TEdit控件中输入已经存在TClientDataSet10笔的A025800680这笔数据。由于这笔数据已经存在于结果数据集中(请参考前图,它位于TClientDataSet一开始的第10笔数据),因此我们会认为TClientDataSet应该可以瞬间找到这笔数据,并且不需要再从后端数据来源中取得额外的数据。

4-24是点击Locate按钮执行查寻数据的结果,从图中我们发现TClientDataSet并不是这样查寻数据,而是先从后端数据来源中取得所有的数据,再进行查寻的工作,因此居然需要花上2.803秒的时间查寻已经在我们眼帘范围之内的数据。说实话这种执行行为实在非常地愚蠢,不过这是LocateLookupFilter等方法内定的行为。尽管如此,聪明的开发人员却可以改善。

在我们继续讨论之前,先看看LocateLookupFilter等方法在执行效率上有没有什么差别。表4-8是使用不同的方法查寻相同的数据结果,从表中我们可以知道它们的查寻效率几乎没有什么明显的差别。

4-24  使用Locate方法查寻数据的结果

4-8

 

Locate

Lookup

Filter

查寻时间

2.803

2.856

2.901

不过当所有的数据下载到TClientDataSet的结果数据集之中后,查寻数据的速度便明显地加快了许多。例如如果我们再次查寻A025800680这笔数据,那么 Locate便只需要花0.01秒的时间,相当快速。接下来的目标便是改善Locate初次查寻数据的效率。

要改善Locate等查寻数据的效率的第一种方法是想办法切断TClientDataSet把后端数据来源中所有数据一次下载到客户端的执行行为。让TClientDataSet在已经存在于结果数据集之中的数据先进行查寻,例如A025800680这笔数据已经存在于结果数据集中,因此如果可以让TClientDataSet先直接在结果数据集中查寻,那么就可以大幅增加效率。

但是要如何切断TClientDataSet和后端数据来源的连接呢?TClientDataSet已经提供了一种方法,那就是CloneCursor

使用CloneCursor查寻数据

TClientDataSet/TSimpleDataSetCloneCursor方法可以让另外一个TClientDataSet/TSimpleDataSet分享相同的数据。但是CloneCursor另外一个没有说明的功能则可以避免TClientDataSet/TSimpleDataSet从后端数据来源下载所有的数据,借助这个隐藏的功能,我们可以先使用CloneCursor方法在结果数据集中查寻数据,如果没有发现需要的数据,那么再让原先的TClientDataSet/TSimpleDataSet使用LocateLookup方法继续查寻数据。这样对于查寻已经存在于结果数据集中的数据而言是非常有效率的。

因此范例应用程序的Smart Locate按钮便使用了下面的程序代码来查寻数据:

procedure TfrmFindData.btnSmartLocateClick(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

      dmFindData.sqlcdsTest.Locate('ID', edtID.Text, [loCaseInsensitive,
        loPartialKey]);

 

    GetEndTime;

    AppMsg('Locate', GetRunTime);

    edtTime2.Text := FloatToStr((GetRunTime) / 1000.0);

    edtRecordCount.Text := IntToStr(dmFindData.sqlcdsTest.RecordCount);

  finally

    aCDS.Free;

  end;

end;

上面的程序代码首先建立一个TClientDataSet控件aCDS,再调用CloneCursor方法从原先的sqlcdsTest这个TSimpleDataSet控件取得另外一个cursor,然后调用aCDSLocate在结果数据集中查寻数据。由于aCDS会避免sqlcdsTest从后端数据来源下载所有的数据,因此它的查寻速度非常良好。图4-25便是使用CloneCursor查寻A025800680这笔数据的结果,我们可以看到它只需要0.004秒,比起直接使用sqlcdsTestLocate快了数百倍。