Загрузка миллионов записей в список строк может быть очень медленной - PullRequest
5 голосов
/ 07 декабря 2011

как я могу очень быстро загрузить миллионы записей из tadotable в список строк?

procedure TForm1.SlowLoadingIntoStringList(StringList: TStringList);
begin
  StringList.Clear;
  with SourceTable do
  begin
    Open;
    DisableControls;
    try
      while not EOF do
    begin
      StringList.Add(FieldByName('OriginalData').AsString);
      Next;
    end;
   finally
   EnableControls;
   Close;
  end;
end;

Ответы [ 6 ]

10 голосов
/ 07 декабря 2011

в вашем цикле вы получите поле. Поиск поля из цикла

procedure TForm1.SlowLoadingIntoStringList(StringList: TStringList); 
var
  oField: TField;
begin
  StringList.Clear;   
  with SourceTable do   
  begin     
    Open;     
    DisableControls;     
    try       
      oField:= FieldByName('OriginalData');
      if oField<>Nil then
      begin
        while not EOF do
        begin       
          StringList.Add(oField.AsString);       
          Next;     
        end;   
      end; 
    finally    
      EnableControls;    
      Close;   
    end; 
  end;  
end;
4 голосов
/ 07 декабря 2011

К сожалению, вы не можете сделать это быстро. Это по сути медленная операция, которая требует большого количества процессорного времени и пропускной способности памяти для достижения. Вы могли бы использовать больше оборудования, но я подозреваю, что вместо этого вам следует переосмыслить свою задачу.

1 голос
/ 07 декабря 2011

С «миллионами записей» вы можете рассмотреть следующие вопросы: 1 / Измените свой запрос с

SELECT * FROM MYTABLE;

на

SELECT OriginalData FROM MYTABLE;

Вы будете использовать меньше памяти и будете более эффективными.

2 / Смотрите другой компонент, кроме TStringList, в зависимости от ваших потребностей.

3 / Смотрите все хорошие предыдущие советы, в основном:

  • не используйте FieldByName
  • прямая ссылка на провайдера OleDB
0 голосов
/ 08 декабря 2011

Расширяя ответ @ Ravaut123, я бы предложил следующий код:

Убедитесь, что ваш запрос не подключен к какому-либо другому визуальному компоненту, и для него не установлены никакие события, которые запускаются в строках строк, потому что это приведет к обновлению при каждом изменении активной записи, замедляя процесс.
Вы можете отключить визуальные элементы управления, используя disablecontrols, но не события и невизуальные элементы управления.

...
SQLatable:= 'SELECT SingleField FROM atable ORDER BY indexedfield ASC';
AQuery:= TAdoQuery.Create(Form1);
AQuery.Connection:= ....
AQuery.SQL.Text:= SQLatable;  

Использование запроса гарантирует, что вы выбираете только 1 поле, в том порядке, в котором вы хотите, это уменьшает сетевой трафик. Таблица выбирает все поля, вызывая гораздо больше накладных расходов.

function TForm1.LoadingAllIntoStringList(AQuery: TAdoQuery): TStringList;  
var 
  Field1: TField; 
begin 
  Result:= nil;
  try
    if not(AQuery.Active) then begin
      AQuery.Open;
    end else begin
      AQuery.First;
    end;
    AQuery.DisableControls;
    AQuery.Filtered:= false;                    //Filter in the SQL `where` clause
    AQuery.FetchAll;                            //Preload all data into memory
    Result:= TStringlist.Create;
  except
    {ignore error, will return nil}
  end;
  try
    Result.Sorted:= false;                      //Make sure you don't enable sorting
    Result.Capacity:= AQuery.RecordCount;       //Preallocate the needed space     
    Field1:= AQuery.FieldByName('SingleField'); //Never use `fieldbyname` in a loop!
    while not AQuery.EOF do begin
      Result.Add(Field1.AsString);
      AQuery.Next;
    end; {while} 
    AQuery.EnableControls;
  except
    FreeAndNil(Result);
  end;   

Если вы хотите загрузить данные в список строк, чтобы выполнить некоторую обработку, попробуйте вместо этого сделать это в операторе SQL. БД может использовать индексы и другие оптимизации, которые не может использовать список строк.
Если вы хотите сохранить эти данные в файл CSV, рассмотрите возможность использования встроенной функции БД для этого.
например MySQL имеет:

SELECT X FROM table1 INTO OUTFILE 'c:/filename_of_csv_file.txt'

Который создаст для вас файл CSV.
Многие БД имеют функции симуляции.

0 голосов
/ 08 декабря 2011

Серьезно? Миллионы записей в списке строк?

Хорошо, давайте предположим, что вам действительно нужен такой подход ...

Уже опубликовано несколько хороших предложений.

Если вы хотите поэкспериментировать с другим подходом, вы можете рассмотреть возможность объединения отдельных частей сервера записей (с помощью хранимой процедуры), а затем вернуть объединенные данные в виде большого двоичного объекта (или, возможно, nvarchar (max)), который в основном является списком связанных строк, разделенных, скажем, возвратом каретки (при условии, что это разумный разделитель для ваших нужд).

Затем можно просто присвоить возвращаемое значение свойству Text в TStringList.

Даже если вы не можете выполнить все строки за один удар, вы можете выполнять их группами, скажем, по 1000 за раз.

Это должно сэкономить вам массу времени на каждой клиентской стороне записи.

0 голосов
/ 07 декабря 2011

отсортировано?

  // Turn off the sort for now
  StringList.Sorted := False;
  // Preallocate the space
  StringList.Capacity := recordCount;
  // Now add the data with Append()
  ...
  // Now turn the sort back on
  StringList.Sorted := True;
...