Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Performance Delphi性能:读取数据集中某个字段下的所有值_Performance_Delphi_List_Tadoquery - Fatal编程技术网

Performance Delphi性能:读取数据集中某个字段下的所有值

Performance Delphi性能:读取数据集中某个字段下的所有值,performance,delphi,list,tadoquery,Performance,Delphi,List,Tadoquery,我们试图从一篇TADOQuery文章中找出一些性能修复。目前,我们使用“while not Q.eof do begin”循环遍历记录。。。下一种方法。对于每个记录,我们读取每个记录的ID和值,并将每个记录添加到组合框列表中 是否有一种方法可以一次性将指定字段的所有值转换为列表?而不是在数据集中循环?如果我能做一些像…这样的事情,那真的很方便 TStrings(MyList).Assign(Q.ValuesOfField['Val']); 我知道这不是一个真正的命令,但这是我正在寻找的概念。寻

我们试图从一篇TADOQuery文章中找出一些性能修复。目前,我们使用“while not Q.eof do begin”循环遍历记录。。。下一种方法。对于每个记录,我们读取每个记录的ID和值,并将每个记录添加到组合框列表中

是否有一种方法可以一次性将指定字段的所有值转换为列表?而不是在数据集中循环?如果我能做一些像…这样的事情,那真的很方便

TStrings(MyList).Assign(Q.ValuesOfField['Val']);

我知道这不是一个真正的命令,但这是我正在寻找的概念。寻找快速响应和解决方案(一如既往,但这是为了解决一个非常紧迫的性能问题)。

您可以尝试将所有数据推送到ClientDataSet并进行迭代,但我认为将数据复制到CD正是您当前正在做的事情—循环和分配

我曾经在服务器上连接值,将其以一个批量传输到客户端,然后再次拆分。这实际上使系统更快,因为它减少了客户端和服务器之间必要的通信

您必须仔细查看性能瓶颈所在的位置。如果您在添加值时不阻止GUI更新,那么它也可以是组合框(特别是当我们谈论20K值时,这需要滚动很多)

编辑:当您无法更改通信时,您也许可以使其异步。在线程中请求新数据,保持GUI响应,在数据存在时填充组合框。这意味着用户可以在5秒钟内看到一个空的组合框,但至少在此期间他可以做其他事情。但不会改变所需的时间。

您无法避免循环。“很长时间”是相对的,但如果检索20000条记录花费的时间太长,则会出现问题

  • 检查您的查询;也许可以改进SQL(缺少索引?)
  • 显示向组合框添加项目的循环代码。也许它可以被优化。(在循环中重复调用
    FieldByName
    ?使用变量检索字段值?)
  • 确保调用
    ComboBox.Items.BeginUpdate和循环后的组合框.Items.EndUpdate
  • 使用探查器查找瓶颈

看看你的评论,这里有一些建议:

在这种情况下,有几件事可能成为瓶颈。第一种是反复查找字段。如果在循环中调用
FieldByName
FindField
,则会浪费CPU时间重新计算一个不会改变的值。对读取的每个字段调用FieldByName一次,并将其分配给局部变量

从字段中检索值时,请调用
AsString
AsInteger
,或其他返回要查找的数据类型的方法。如果您正在读取
TField.Value
属性,则在
variant
转换上浪费时间

如果要向Delphi组合框中添加一组项,则可能需要处理
items
属性形式的字符串列表。设置列表的
Capacity
属性,并确保在开始更新之前调用
BeginUpdate
,最后调用
EndUpdate
。这可以实现一些内部优化,从而加快加载大量数据的速度

根据您使用的组合框,它可能在处理其内部列表中的大量项时遇到一些问题。看看它是否有一个“虚拟”模式,在这个模式中,你不需要预先加载所有内容,只需告诉它需要多少项,当它被放下时,它会为屏幕上应该显示的每个项调用一个事件处理程序,然后你给它显示正确的文本。这确实可以加快某些UI控件的速度

当然,您还应该确保数据库查询本身是快速的,但是SQL优化超出了这个问题的范围


最后,米凯尔·埃里克森的评论绝对值得关注

不确定这是否有帮助,但我的建议是不要直接添加到
组合框中。改为加载到本地
TStringList
,使其尽可能快,然后使用
TComboBox.Items.AddStrings
一次性添加它们:

var
  SL: TStringList;
  Fld: TField;
begin
  SL := TStringList.Create;
  Fld := AdoQuery1.FieldByName('ListFieldName'); 
  try
    SL.Sorted := False; // Sort in the query itself first
    SL.Capacity := 25000; // Some amount estimate + fudge factor
    SL.BeginUpdate;  
    try
      while not AdoQuery1.Eof do
      begin
        SL.Append(Fld.AsString);
        AdoQuery1.Next;
      end;
    finally
      SL.EndUpdate;
    end;
    YourComboBox.Items.BeginUpdate;
    try
      YourComboBox.Items.AddStrings(SL);
    finally
      YourComboBox.Items.EndUpdate;
    end;
  finally
    SL.Free;
  end;
end;

您的查询是否也与一些数据感知控件或TDataSource关联?如果是这样,请在DisableControls和EnableControls块中执行循环,这样视觉控件不会在每次移动到新记录时更新

项目列表是否相当静态?如果是这样,请考虑在应用程序启动时创建一个组合框的非可视实例,或者在一个单独的线程中创建,然后在创建表单时将非可视组合框分配给VisualCo框。指定感兴趣的列,它将返回一个包含值的数组。在我的测试中,向组合框中添加22000行所需的时间从使用
而不是ADOQuery1.Eof…
循环的7秒增加到1.3秒

示例代码:

var
  V: Variant;
  I: Integer;
begin
  V := ADOQuery1.Recordset.GetRows(adGetRowsRest, EmptyParam, 'ColumnName');

  for I:= VarArrayLowBound(V, 2) to VarArrayHighBound(V, 2) do
    ComboBox1.Items.Add(V[0, I]));
end;
如果要在数组中包含多个列,则应使用变量数组作为第三个参数

V := ADOQuery1.Recordset.GetRows(adGetRowsRest, EmptyParam, 
       VarArrayOf(['ColumnName1', 'ColumnName2']);

其他人提出了一些很好的性能建议,您应该在Delphi中实现这些建议。你应该考虑他们。我将重点介绍ADO

您还没有指定后端数据库服务器是什么,所以我不能说得太具体,但您应该了解ADO

ADO记录集

在ADO中,有一个记录集对象。在本例中,该记录集对象基本上就是您的结果集。遍历记录集的有趣之处在于,它仍然与提供者耦合

光标类型

如果光标类型为动态或Delphi的默认键集,则每次记录集从提供程序请求新行时
   var
  SL: TStringList;
  Fld: TField;
begin
  SL := TStringList.Create;
  AdoQuery1.DisableControls;
  Fld := AdoQuery1.FieldByName('ListFieldName'); 
  try
    SL.Sorted := False; // Sort in the query itself first
    SL.Capacity := 25000; // Some amount estimate + fudge factor

    SL.BeginUpdate;  
    try
      while not AdoQuery1.Eof do
      begin
        SL.Append(Fld.AsString);
        AdoQuery1.Next;
      end;
    finally
      SL.EndUpdate;
    end;

    YourComboBox.Items.AddStrings(SL);

  finally
    SL.Free;
    AdoQuery1.EnableControls;
  end;
end;