为什么我的代码这么慢?

Maw*_*awg 5 delphi profiling ado tstringgrid

对于那些没有时间进入但可能有类似问题的人来说,最热门的(抱歉)答案.

规则#1一如既往地尽可能地从循环中移动.
2,移动TField var:= ADODataSet.FieldByname()退出循环3,ADODataSet.DisableControls(); 和ADODataSet.EnableControls(); 在循环4周围,stringGrid.Rows [r] .BeginUpdate()和EndUpdate()在每一行(不能做到控制)每一个剃掉几秒钟,我把它降到"比眼睛快可以看到"通过改变

loop
  stringGrid.RowCount := stringGrid.RowCount + 1;
end loop
Run Code Online (Sandbox Code Playgroud)

放在stringGrid.RowCount := ADODataSet.RecordCount;循环之前

+1并衷心感谢所有帮助过的人.

(现在我会去看看我能做些什么来优化绘制TChart,这也很慢;-)


在表中大约有3,600行,这需要45秒来填充字符串网格.我究竟做错了什么?

   ADODataSet := TADODataSet.Create(Nil);
   ADODataSet.Connection := AdoConnection;

   ADODataSet.CommandText := 'SELECT * FROM measurements';
   ADODataSet.CommandType := cmdText;
   ADODataSet.Open();

   while not ADODataSet.eof do
   begin
      TestRunDataStringGrid.RowCount := TestRunDataStringGrid.RowCount + 1;

      measurementDateTime   := UnixToDateTime(ADODataSet.FieldByname('time_stamp').AsInteger);
      DoSQlCommandWithResultSet('SELECT * FROM start_time_stamp', AdoConnection, resultSet);
      startDateTime := UnixToDateTime(StrToInt64(resultSet.Strings[0]));
      elapsedTime   := measurementDateTime - startDateTime;
      TestRunDataStringGrid.Cells[0, Pred(TestRunDataStringGrid.RowCount)] := FormatDateTime('hh:mm:ss', elapsedTime);
      TestRunDataStringGrid.Cells[1, Pred(TestRunDataStringGrid.RowCount)] := FloatToStrWithPrecision(ADODataSet.FieldByname('inputTemperature').AsFloat);
      TestRunDataStringGrid.Cells[2, Pred(TestRunDataStringGrid.RowCount)] := FloatToStrWithPrecision(ADODataSet.FieldByname('outputTemperature').AsFloat);
      TestRunDataStringGrid.Cells[3, Pred(TestRunDataStringGrid.RowCount)] := FloatToStrWithPrecision(ADODataSet.FieldByname('flowRate').AsFloat);
      TestRunDataStringGrid.Cells[4, Pred(TestRunDataStringGrid.RowCount)] := FloatToStrWithPrecision(ADODataSet.FieldByname('waterPressure').AsFloat * convert);
      TestRunDataStringGrid.Cells[5, Pred(TestRunDataStringGrid.RowCount)] := FloatToStrWithPrecision(ADODataSet.FieldByname('waterLevel').AsFloat);
      TestRunDataStringGrid.Cells[6, Pred(TestRunDataStringGrid.RowCount)] := FloatToStrWithPrecision(ADODataSet.FieldByname('cod').AsFloat);
      ADODataSet.Next;
   end;

   ADODataSet.Close();
   ADODataSet.Free();

更新:

Function  DoSQlCommandWithResultSet(const command : String; AdoConnection : TADOConnection; resultSet : TStringList): Boolean;
  var
        i : Integer;
        AdoQuery : TADOQuery;

begin
  Result := True;
  resultSet.Clear();

  AdoQuery := TADOQuery.Create(nil);
  try
    AdoQuery.Connection := AdoConnection;
    AdoQuery.SQL.Add(command);
    AdoQuery.Open();
    i := 0;
    while not  AdoQuery.eof do
    begin
      resultSet.Add(ADOQuery.Fields[i].Value);
      i := i + 1;
      AdoQuery.Next;
    end;

  finally
    AdoQuery.Close();
    AdoQuery.Free();
  end;
end;

Lar*_*tig 10

  1. 您正在执行命令SELECT * FROM start_time_stamp3,600次,但在我看来它并不以任何方式与您的外部循环相关联.为什么不在循环之前执行一次?

  2. SELECT命令似乎只返回单个记录的单个列,但是您使用"*"来加载所有列,而没有WHERE子句将结果限制为单个行(如果表中有多个行).

  3. 您仅使用Measurements中的有限数量的列,但使用"*"检索所有列.

  4. 您没有显示内容DoSQlCommandWithResultSet,因此不清楚该例程是否存在问题.

  5. 目前尚不清楚问题是在您的数据库访问还是字符串网格中.注释掉与字符串网格相关的所有行并运行程序.单独访问数据库需要多长时间?


da-*_*oft 9

除了拉里劳斯蒂格点:

  1. 通常,FieldByName是相对较慢的方法.您在循环中为相同的字段调用它.将获取字段引用移出循环并将引用存储在变量中.喜欢:InputTempField := ADODataSet.FieldByname('inputTemperature');
  2. 您正在循环中调整网格的大小TestRunDataStringGrid.RowCount := TestRunDataStringGrid.RowCount + 1.就是这种情况,你应该ADODataSet.RecordCount在循环之前使用:TestRunDataStringGrid.RowCount := ADODataSet.RecordCount.
  3. 这是ADODataSet.DisableControls在循环和ADODataSet.EnableControls循环之前调用的一个好习惯.更实际的是ADO数据集,它没有最佳实现,而且这些调用有帮助.
  4. 根据您使用的DBMS,您可以通过设置更大的"行集大小"来提高提取性能.不确定,它如何在ADO中控制,可能将ADODataSet.CacheSize设置为更大的值将有所帮助.还有,光标设置:)


Joe*_*yer 5

您应该为每个字段声明类型为TField的局部变量,而不是在循环内调用ADODataSet.FieldByname('Fieldname'),将ADODataset.FindField('Fieldname')分配给变量并使用循环内的变量.FindFieldByName会在每次调用时搜索列表.

更新:

procedure TForm1.Button1Click(Sender: TObject);
var
  InputTemp, OutputTemp: TField;
begin
  ADODataSet := TADODataSet.Create(Nil);
  try
    ADODataSet.Connection := ADOConnection;
    ADODataSet.CommandText := 'SELECT * FROM measurements';
    ADODataSet.Open;
    InputTemp := ADODataSet.FindField('inputTemperature');
    OutputTemp := ADODataSet.FindField('outputTemperature');
    // assign more fields here
    while not ADODataSet.Eof do begin
      // do something with the fields, for example:
      // GridCell := Format ('%3.2f', [InputTemp.AsFloat]);
      // GridCell := InputTemp.AsString;
      ADODataSet.Next;
    end;
  finally
    ADODataSet.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

另一种选择是将TADODataset Componont放在表单上(或使用TDataModule)并在设计时定义字段.