在SQLite,FireDac,Delphi中插入记录时内存不足

时间:2017-08-31 07:06:59

标签: sqlite delphi firedac

我有一个Delphi应用程序,它通过FireDac组件TFDTable将大约200,000条记录(大约1GB)插入到SQLite数据库中。当它插入时,我可以看到应用程序内存增加,直到我得到一个" Out of Memory Error"。我猜它有缓存和分页的东西,但我找不到任何修复它没有关闭和重新打开数据库每1000条记录左右。想法?

...编辑 对不起,措辞薄弱的问题...... 代码很简单,所以我没有包含它,但看起来基本上是这样的:

procedure DoIt;
begin
  myDB.Insert;
  myDBField1.AsString := StringOfChar('-',1000);
  myDB.Post;
end;

现在,我预计内存可能会增加,因为字符串很可能被复制到数据库缓存中。如果我使用GetMemoryManagerState()查看分配,我实际上可以看到这一点。我希望在某些时候,当数据写入光盘时,缓存中的内存将被刷新。但是,它似乎不是。它一直持续下去,直到我得到一个" Out of Memory"错误。

通常,除了在连接中选择sqlite并向表中添加字段外,大多数对象属性都设置为默认状态。

我知道这里没有太多东西要去。但我并不认为这也会失败,我希望有人可能有类似的问题。

1 个答案:

答案 0 :(得分:2)

TFDTable是查询对象的瘦包装器,可以构建用于与底层DBMS表一起操作的SQL命令。它有自己的存储(Table对象),它存储提取到客户端的数据以及您插入的元组。但是所有这些都在内存中,没有底层文件缓存。

尽管可以在插入时清除内部存储空间,但TFDTable不是插入数据量的好对象。更好地使用TFDQuery之类的查询对象,它与称为Array DML的批处理命令执行技术相结合,可以为您带来真正的性能提升,即使对于本地DBMS引擎也是如此。并且TFDQuery不会缓存插入的元组。

当您使用索引参数绑定时,FireDAC本身支持SQLite的这种技术,例如:此代码应插入200次批量的1000个唯一元组:

const
  BatchSize = 1000;
  TotalSize = 200000;
var
  Batch: Integer;
  Index: Integer;
begin
  FDQuery.SQL.Text := 'INSERT INTO MyTable VALUES (:p1, :p2)';
  FDQuery.Params.BindMode := pbByNumber;
  FDQuery.Params.ArraySize := BatchSize;

  for Batch := 0 to TotalSize div BatchSize - 1 do
  begin
    for Index := 0 to BatchSize - 1 do
    begin
      FDQuery.Params[0].AsIntegers[Index] := (Batch * BatchSize) + Index;
      FDQuery.Params[1].AsWideStrings[Index] := 'Some Unicode string value';
    end;
    FDQuery.Execute(BatchSize, 0);
  end;
end;