2011-01-22 4 views
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, который также медленно ;-)


около 3600 строк в таблице это занимает 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; 

+0

Лучшим способом подойти ответ является каким-то своим кодом. Кроме того, нет понятия, сколько строк должно быть возвращено 'select * from time_stamp'; может быть, это миллион строк? – 9000

+0

+1 Спасибо. Любые рекомендации по профилированию? В этом случае я делал измерения с интервалом в одну секунду в течение примерно одного часа (плюс/минус несколько секунд) – Mawg

+1

Вам следует попробовать SamplingProfiler, доступный по адресу http://delphitools.info/samplingprofiler. Это дает вам хороший взгляд на то, на что тратит ваша программа время, хорошо работает с приложениями Delphi, и это бесплатно. :) –

ответ

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. В зависимости от используемой СУБД вы можете улучшить производительность загрузки, установив более крупный «размер набора строк». Не уверен, как он управляется в ADO, возможно, при настройке ADODataSet.CacheSize на большее значение поможет. Кроме того, есть настройки курсора :)
+0

+1 Спасибо. # 1 и 2, безусловно, хорошие идеи (вы говорите, что InputTempField является TField, и я использую InputTempField.AsFloat в цикле?). Я уже взял № 3 на борту. Для # 4 я немного n00b, так что оставим это на потом. Кроме того, он должен быть подателем жалобы ODBC. – Mawg

+0

Да InputTempField: TField. –

+0

TestRunDataStringGrid.RowCount: = ADODataSet.RecordCount; оказалось, что изменилось. Некоторые другие помогают, но это действительно так. См. Обновленный вопрос для большей разницы – Mawg

10
  1. Вы выполняете команду SELECT * FROM start_time_stamp 3600 раз, но это не кажется мне, что она коррелирует с внешним контуром в любом случае. Почему бы не выполнить его один раз перед циклом?

  2. Эта команда SELECT возвращает только один столбец одной записи, но вы используете «*» для загрузки всех столбцов и без предложения WHERE, чтобы ограничить результаты одной строкой (если имеется более одной строки в таблице).

  3. Вы используете только ограниченное количество столбцов из Measurements, но вы извлекаете все столбцы с помощью «*».

  4. Вы не можете видеть содержимое DoSQlCommandWithResultSet, поэтому неясно, есть ли проблема в этой рутине.

  5. Неясно, находится ли проблема в доступе к базе данных или в сетке строк. Прокомментируйте все строки, относящиеся к строковой сетке, и запустите программу. Сколько времени занимает доступ к базе данных?

+0

+1 отличная обратная связь, спасибо. – Mawg

+0

Вернитесь и сообщите нам, что вы найдете. –

+0

+1 отличная обратная связь, спасибо. 1) d'oh! Я перемещаю это до цикла 2) хорошая пинта 3) на самом деле я хочу получить доступ к каждому полю «измерений». В этом случае SELECT * приемлемо? 4), что может быть проблемой. Он обращается к тому же соединению ADO. Я разместил код выше. – Mawg

2

В дополнение к ответу Ларри Lustig, рассмотреть возможность использования data-aware управления вместо этого, как компонент alt textTDbGrid.

+0

+1 Спасибо. По-прежнему googling вокруг для некоторых примеров кодирования – Mawg

5

Вместо вызова ADODataSet.FieldByname ('Fieldname') внутри цикла вы должны объявить локальные переменные типа TField для каждого поля, присвоить переменные переменные ADODataset.FindField ('Fieldname') и использовать переменные внутри цикла. FindFieldByName ищет список с каждым вызовом.

Update:

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; 

Другим вариантом было бы уронить TADODataSet Componont на форме (или используйте TDataModule) и определить поля на этапе проектирования.

+0

+1 Могу ли я использовать TFloatField, если я знаю, что это float? Если нет, можете ли вы опубликовать несколько строк, чтобы я мог видеть, как это сделать? Спасибо – Mawg

+1

добавлен образец кода –

2

Если вы не используете средства управления данными, вы должны знать, использовать TestRunDataStringGrid.BeginUpdate до и TestRunDataStringGrid.EndUpdate после цикла. Без этого ваша сетка постоянно перерисовывается после каждой модификации (добавление новой строки, обновление ячейки).

Еще один советник задает AdoQuery.LockType := ltReadOnly перед тем, как открыть запрос.

1

Вы также можете попробовать измерительный профилировщик вместо профилировщика пробоотбора, чтобы получить лучшие результаты (пробоотборщики пробоотборов пропускают информацию о деталях, и в большинстве случаев у них меньше 1000 выборок в секунду, а 1000 уже низок: только хорошо получить краткий обзор).

Инструментирования профайлеров: