5

時間がなくても同様の問題を抱えている可能性がある人のために、トップに投稿された(申し訳ありません)回答。

ルール 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

stringGrid.RowCount := ADODataSet.RecordCount;ループの前に置く

+1、そして助けてくれたすべての人に心から感謝します。

(ここで、TChart の描画を最適化するために何ができるかを見ていきますが、これも遅いです ;-)


テーブルに約 3,600 行あるため、文字列グリッドに入力するのに 45 秒かかります。私は何を間違っていますか?

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

   ADODataSet.CommandText := 'SELECT * FROM 測定値';
   ADODataSet.CommandType := cmdText;
   ADODataSet.Open();

   while not ADODataSet.eof do
   始める
      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]));
      経過時間:=測定日時 - 日時の開始;
      TestRunDataStringGrid.Cells[0、Pred(TestRunDataStringGrid.RowCount)] := FormatDateTime('hh:mm:ss'、経過時間);
      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;
   終わり;

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

アップデート:

Function DoSQlCommandWithResultSet(const command : String; AdoConnection : TADOConnection; resultSet : TStringList): Boolean;
  変数
        i : 整数。
        AdoQuery : TADOQuery;

始める
  結果:=真;
  resultSet.Clear();

  AdoQuery := TADOQuery.Create(nil);
  試す
    AdoQuery.Connection:= AdoConnection;
    AdoQuery.SQL.Add(コマンド);
    AdoQuery.Open();
    私:= 0;
    while not AdoQuery.eof do
    始める
      resultSet.Add(ADOQuery.Fields[i].Value);
      私 := 私 + 1;
      AdoQuery.Next;
    終わり;

  最後に
    AdoQuery.Close();
    AdoQuery.Free();
  終わり;
終わり;

4

6 に答える 6

10
  1. コマンドをSELECT * FROM start_time_stamp3,600 回実行していますが、外部ループと何らかの形で相関しているようには見えません。ループの前に一度実行してみませんか?

  2. その SELECT コマンドは 1 つのレコードの 1 つの列のみを返すように見えますが、「*」を使用してすべての列をロードし、結果を 1 つの行に制限する WHERE 句を使用しません (テーブルに複数の行がある場合)。

  3. Measurements から限られた数の列のみを使用しますが、"*" を含むすべての列を取得します。

  4. の内容を表示しないDoSQlCommandWithResultSetため、そのルーチンに問題があるかどうかは明確ではありません。

  5. 問題がデータベース アクセスにあるのか、文字列グリッドにあるのかは明らかではありません。文字列グリッドに関連するすべての行をコメント アウトし、プログラムを実行します。データベースへのアクセスだけでどのくらいの時間がかかりますか?

于 2011-01-22T03:45:16.447 に答える
9

Larry Lustig のポイントに加えて:

  1. 一般に、FieldByName は比較的遅いメソッドです。同じフィールドに対してループで呼び出しています。フィールド参照の取得をループの外に移動し、参照を変数に格納します。お気に入り:InputTempField := ADODataSet.FieldByname('inputTemperature');
  2. ループ内でグリッドのサイズを変更していますTestRunDataStringGrid.RowCount := TestRunDataStringGrid.RowCount + 1ADODataSet.RecordCountこれは、ループの前に使用する必要がある場合です: TestRunDataStringGrid.RowCount := ADODataSet.RecordCount
  3. ADODataSet.DisableControlsこれは、ループの前とループの後に呼び出すことをお勧めしADODataSet.EnableControlsます。最適な実装がなく、それらの呼び出しが役立つADOデータセットの場合はさらに現実的です。
  4. 使用している DBMS によっては、「行セット サイズ」を大きく設定することで、フェッチのパフォーマンスを向上させることができます。ADO でどのように制御するかは不明ですが、おそらく ADODataSet.CacheSize をより大きな値に設定すると役立つでしょう。また、カーソル設定もあります:)
于 2011-01-22T07:57:49.283 に答える
5

ループ内で ADODataSet.FieldByname('Fieldname') を呼び出す代わりに、フィールドごとに TField 型のローカル変数を宣言し、変数に 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;

もう 1 つのオプションは、TADODataset Componont をフォームにドロップして (または TDataModule を使用して)、設計時にフィールドを定義することです。

于 2011-01-22T05:48:52.743 に答える
2

Larry Lustig の回答に加えて、代わりにコンポーネントdata-awareのようなコントロールを使用することを検討してください。代替テキスト TDbGrid

于 2011-01-22T04:36:31.217 に答える
2

データベース対応コントロールを使用していない場合は、TestRunDataStringGrid.BeginUpdate前ループとTestRunDataStringGrid.EndUpdate後ループを使用する必要があります。これがないと、変更のたびにグリッドが常に再描画されます (新しい行の追加、セルの更新)。

AdoQuery.LockType := ltReadOnlyクエリを開く前に、別のヒントが設定されます。

于 2011-01-22T09:17:29.533 に答える
1

より良い結果を得るために、サンプリング プロファイラーの代わりにインストルメント プロファイラーを試すこともできます (サンプリング プロファイラーは多くの詳細情報を見逃しており、ほとんどの場合、1 秒あたりのサンプル数は 1000 未満であり、1000 は既に低いため、簡単な概要を取得するのに適しています)。 )。

プロファイラーの計測:

于 2011-01-24T08:03:09.520 に答える