【问题标题】:ADOQuery.Locate Slow, Create IndexADOQuery.Locate 慢,创建索引
【发布时间】:2020-04-16 08:51:11
【问题描述】:

我有以下行来定位查询中的一行。

if Query.Locate('Line;Hour;Minute',VarArrayOf([Line-400,AHour,minuteof(Start)]),[]) = true then

这很慢,现在我记得可以将索引添加到查询中,以便定位本身快几倍。不幸的是,我似乎找不到示例。

有人可以帮帮我吗? 问候 罗伯特

【问题讨论】:

  • 你使用的是什么数据库后端?
  • Microsoft SQL Server

标签: sql-server delphi tadoquery


【解决方案1】:

有趣的问题。

更新请参阅下面的更新。

我在我的 SS2014 Sql Server 上设置了一些测试数据,以使用如下代码运行一些测试:

ID := 1;
for Line := 1 to 1000 do begin
  for AHour := 1 to 24 do begin
    for AMinute := 1 to 60 do begin
      AdoQuery1.InsertRecord([ID, Line, AHour, AMinute]);
      Inc(ID);
      end;
    end;
  end;
end;

然后,我进行了一些类似这样的测试

procedure TForm1.LocateTest1(DisableControls, UseSort : Boolean);
var
  T1 : Integer;
  Line,
  AHour,
  AMinute : Integer;
begin

  AdoQuery1.Sql.Text := 'select * from linetest order by line, ahour, aminute';
  AdoQuery1.CursorLocation := clUseClient;
  AdoQuery1.Open;
  T1 := GettickCount;
  if DisableControls then
    AdoQuery1.DisableControls;

  if UseSort then
    AdoQuery1.Recordset.Sort := 'Line,AHour,AMinute';
  Line := 1000;
  AHour := 23;
      for AMinute := 60 downto 1 do begin
        if not AdoQuery1.Locate('Line;AHour;AMinute', VarArrayOf([Line, AHour, AMinute]), []) then
          Caption := Format('Locate failed %d %d %d', [Line, AHour, AMinute]);
      end;
  Memo1.Lines.Add('Test1 : ' + IntToStr(GetTickCount - T1));
  if DisableControls then
    AdoQuery1.EnableControls;
  AdoQuery1.Close;
end;

涉及Disable/EnableControls的原因是因为我报告的结果 这里Why does scrolling through ADOTable get slower and slower? ,即使没有 db-aware,调用 DisableControls 也会对滚动速度产生巨大影响 涉及的控制。

但是,滚动似乎不会对在 TAdoQuery 上执行 Locate() 产生重大影响,因为调用 DisableControls 只花费了大约 1.5 秒的记录时间 26 秒。显然,TAdoQuery.Locate 在处理大量行时表现不佳。

UseSort 参数的想法是查看是否将 RecordSet 排序在 AdoQuery 对速度有任何影响,但没有,原因是 Locate 调用 无论如何都使用排序的 TCustomAdoDataSet.LocateRecord。

您提到了添加索引。不幸的是,TAdoQuery 只支持使用服务器端索引 在执行 thq SQL 查询时,未在检索到的结果集中定位记录。您可以添加 TAdoTable 的客户端索引,但根据与上述类似的测试,令我惊讶的是, 他们做了 与 Locate() 的速度几乎没有区别。

所以,鉴于我目前的结果,使用参数化的方法似乎更快 SELECT 仅检索当前感兴趣的行,而不是尝试定位它 在一个大的测试集中。 Alterantaivel,您可以通过 DatasetProvider 或 FireDAC FDMemTable 等将结果集检索到 ClientDataSer 中。Ymmv,这取决于您正在做什么...

更新自从发布我的原始答案以来,我还有一些进一步的更新 包括它可能是有用的。

  • 一种方法是使用调用 AdoQuery 的 RecordSet 的 Find 和 Filter 方法来模拟 Locate 的方法,该方法比重复执行 AdoQuery1.Locate 快得多(大约 15 秒)。我仍在对此进行调查,并将在一两天内发布另一个更新。

  • 另一个是简单地提到做定位是做 FireDAC FDQuery 而不是 AdoQuery。使用以下代码,这似乎与 AdoQuery 在 9 秒内执行相同的定位集需要大约 25 秒:

使用 FDQuery.Locate

procedure TForm2.LocateTest;
var
  T1 : Integer;
  Line,
  AHour,
  AMinute : Integer;
begin

  FDQuery1.Sql.Text := 'select * from linetest order by line, ahour desc, aminute desc';
  //FDQuery1.CursorLocation := clUseClient;
  FDQuery1.CursorKind := ckForwardOnly;
  FDQuery1.Open;

  T1 := GettickCount;
  Line := 1000;
  AHour := 1;

  for AMinute := 1 to 60 do begin
    if not FDQuery1.Locate('Line;AHour;AMinute', VarArrayOf([Line, AHour, AMinute]), []) then
      Caption := Format('Locate failed %d %d %d', [Line, AHour, AMinute]);
  end;

  Memo1.Lines.Add('Test1 : ' + IntToStr(GetTickCount - T1));
  FDQuery1.Close;
end;

【讨论】:

  • 谢谢你,那我可能已经想到了。我本可以发誓一旦收到记录集就可以索引,但可能是我的想象力在玩弄我。无论如何我做了什么,因为我在做与此平行的实验。我打开表并将所有数据插入到动态数组中。然后我操作动态数组。我只想做一个选择,因为我从同一张表中创建了很多图表。而且我注意到进行多项选择比一次大选择要慢。 10 秒缩短到 3 秒。
  • 我在找这个 BQuery.Fields['Line'].Properties.Item['Optimize'].Value:=true;但这并没有帮助。最后,我需要重新考虑整个事情。我意识到我不需要 locate 。因为我已经订购了 Items 。相反,我有一个 IF ELSE ,在那里我检查 Row 是否与当前期间匹配,如果是,我会获取数据并执行 BQuery.Next 否则我将继续下一步。相同的结果更好的性能。
【解决方案2】:

文档说Locate 将光标移动到与特定搜索条件匹配的第一行
如果您的表有很多记录,则定位会
Locate 通常用于本地数据库,但在客户端-服务器 RDBM 中,最好使用带有 WHERESQL 来最大限度地减少搜索时间并最大限度地减少数据流量。 p>

【讨论】:

    猜你喜欢
    • 2020-12-17
    • 1970-01-01
    • 1970-01-01
    • 2014-12-15
    • 2019-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多