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

Out of memory when inserting records in SQLite, FireDac, Delphi

我有一个 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 和向 table 添加字段外,大多数对象属性都设置为默认状态。

我知道这里没有太多内容可以继续。但我也不认为这会失败,我希望有人可能遇到过类似的问题。

TFDTable is a thin wrapper around a query object that can build SQL commands for operating with the underlying DBMS table. It has its own storage (Table 对象),它存储提取到客户端的数据以及您插入的元组。但是所有这些都在内存中,没有底层文件缓存。

尽管可以在插入时清除内部存储,TFDTable is not a good object for inserting data in such amount. Better use query object like TFDQuery which in combination with a batch command execution technique called Array DML can bring you real performance increase, even for local DBMS engine. And 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;