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

Jer*_*dge 7 delphi performance list tadoquery

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

有没有办法将指定字段的所有值一次性转换为列表?而不是循环数据集?如果我可以做一些像...那样的话真的很方便

TStrings(MyList).Assign(Q.ValuesOfField['Val']);
Run Code Online (Sandbox Code Playgroud)

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

Mas*_*ler 13

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

在这种情况下,有一些事情可能成为瓶颈.第一个是重复查看字段.如果你正在调用FieldByNameFindField在你的循环中,你浪费CPU时间重新计算一个不会改变的值.为您正在读取的每个字段调用一次FieldByName,并将它们分配给局部变量.

从字段中检索值时,调用AsStringAsInteger返回您要查找的数据类型的其他方法.如果您正在阅读TField.Value酒店,那么您在浪费时间进行variant转换.

如果你要将一堆项添加到Delphi组合框中,那么你可能正在以Items属性的形式处理字符串列表.设置列表的Capacity属性并确保BeginUpdate在开始更新之前调用,并EndUpdate在结束时调用.这可以实现一些内部优化,从而加快大量数据的加载速度.

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

此外,您应该确保数据库查询本身很快,但SQL优化超出了本问题的范围.

最后,Mikael Eriksson的评论绝对值得关注!

  • 提前设置`容量'的好主意! (2认同)

Mik*_*son 9

你可以使用Getrows.您指定您感兴趣的列,它将返回一个包含值的数组.将22.000行添加到组合框所需的时间从while not 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;
Run Code Online (Sandbox Code Playgroud)

如果您希望数组中有多个列,则应使用变量数组作为第三个参数.

V := ADOQuery1.Recordset.GetRows(adGetRowsRest, EmptyParam, 
       VarArrayOf(['ColumnName1', 'ColumnName2']);
Run Code Online (Sandbox Code Playgroud)


Mar*_*ams 3

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

您还没有指定后端数据库服务器是什么,所以我不能太具体,但是您应该了解一些关于 ADO 的事情。

ADO记录集

在ADO中,有一个RecordSet对象。在这种情况下,RecordSet 对象基本上就是您的 ResultSet。迭代 RecordSet 的有趣之处在于它仍然与提供者耦合。

光标类型

如果您的游标类型是 Dynamic 或 Delphi 的默认 Keyset,那么每次 RecordSet 向提供者请求新行时,提供者都会在返回记录之前检查是否有任何更改。

因此,对于 TADOQuery,您所做的只是读取结果集以填充组合框,并且它不太可能发生更改,您应该使用静态游标类型来避免检查更新的记录。

如果您不知道光标是什么,当您调用 Next 之类的函数时,您正在移动光标,它代表当前记录。

并非每个提供程序都支持所有游标类型。

缓存大小

Delphi 和 ADO 的 RecordSet 默认缓存大小为 1。即 1 条记录。这与光标类型结合使用。缓存大小告诉 RecordSet 一次要获取和存储多少条记录。

当您发出高速缓存大小为 1 的 Next(实际上是 ADO 中的 MoveNext)之类的命令时,RecordSet 在内存中仅具有当前记录,因此当它获取下一条记录时,它必须再次向提供者请求该记录。如果游标不是静态的,则提供程序有机会在返回下一条记录之前获取最新数据。因此,大小 1 对于 Keyset 或 Dynamic 有意义,因为您希望提供程序能够为您获取更新的数据。

显然,值为 1 时,每次移动光标时提供者和 RecordSet 之间都会进行通信。好吧,如果游标类型是静态的,那么这是我们不想要的开销。因此,增加缓存大小将减少 RecordSet 和提供者之间的往返次数。这也会增加您的内存要求,但速度应该更快。

另请注意,当键集游标的缓存大小大于 1 时,如果您想要的记录位于缓存中,它将不会再次向提供者请求它,这意味着您将看不到更新。