将数百万条记录加载到字符串列表中可能会非常慢

时间:2011-12-07 11:18:13

标签: delphi tstringlist tadotable

我如何能够非常快速地将数百万条记录从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 个答案:

答案 0 :(得分:10)

在你的循环中,你得到了这个领域。 从循环中搜索字段

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;

答案 1 :(得分:4)

不幸的是,你不能快速做到这一点。这是一个固有的慢速操作,需要大量的CPU时间和内存带宽才能实现。你可以投入更多的硬件,但我怀疑你应该重新考虑你的任务。

答案 2 :(得分:1)

有'数百万条记录',您可以考虑: 1 /更改您的查询

SELECT * FROM MYTABLE;

in

SELECT OriginalData FROM MYTABLE;

您将使用更少的内存并提高效率。

2 /根据您的需要,查看除TStringList之外的其他组件。

3 /看看以前所有好的建议,主要是:

  • 不要使用FieldByName
  • 指向OleDB提供商的直接链接

答案 3 :(得分:0)

是否排序?

  // 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;

答案 4 :(得分:0)

真的?字符串列表中的数百万条记录?

好的,我们假设您确实需要采用这种方法......

已经发布了一些好的建议。

如果你想尝试不同的方法,可以考虑连接单个记录服务器端(通过存储过程),然后将连接数据作为blob(或可能是nvarchar(max))返回,这基本上就是列表由回车符分隔的连接字符串(假设这是符合您需要的合理分隔符)。

然后,您可以简单地将返回的值分配给TStringList的Text属性。

即使您不能在一次点击中完成所有字符串,您也可以一次以1000个为一组进行操作。

这样可以节省大量时间在每个记录客户端循环。

答案 5 :(得分:0)

扩展@ 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语句中执行此操作。 DB可以使用stringlist不能使用的索引和其他优化 如果要将该数据保存到CSV文件中,请考虑使用内置数据库功能。
例如MySQL有:

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

将为您创建CSV文件。
许多DB都具有类似的功能。