【问题标题】:Out of memory when inserting records in SQLite, FireDac, Delphi在 SQLite、FireDac、Delphi 中插入记录时内存不足
【发布时间】:2017-08-31 07:06:58
【问题描述】:

我有一个 Delphi 应用程序,它通过 FireDac 组件 TFDTable 将大约 200,000 条记录(约 1GB)插入 SQLite 数据库。当它插入时,我可以看到应用程序内存在增加,直到出现“内存不足错误”。我猜它与缓存和分页有关,但我找不到任何可以修复它的东西,除了每 1000 条记录左右关闭和重新打开数据库。想法?

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

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

现在,我预计内存可能会增加,因为字符串可能会复制到数据库缓存中。如果我使用 GetMemoryManagerState() 查看分配,我实际上可以看到这一点。我希望在某个时候,缓存中的内存会在数据写入磁盘时被刷新。然而,似乎并非如此。它会一直运行,直到我收到“内存不足”错误。

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

我知道这里没什么可做的。但我也不认为这会失败,我希望有人可能遇到过类似的问题。

【问题讨论】:

  • 您如何发布一些重现该问题的代码?此外,您的 Delphi/FireDAC 版本可能很重要。
  • 我们无法调试故事。请参阅:minimal reproducible example。如果不是,至少向我们展示一些相关代码。
  • 数据感知组件会带来相当多的开销,这可能会妨碍真正大型但直接的工作。这就是为什么我在 sqlite DLL 周围创建了一个“干净”的包装器:github.com/stijnsanders/TSQLite
  • 有一个底层数据存储,如果您不将数据提交到 DBMS 中,该存储自然会缓存它们并增长。在没有看到您的代码的情况下很难在这里提出建议,但至少考虑使用 Array DML technique 批量执行。
  • 您需要客户端的数据吗?我没有使用 FireDAC 的经验,但是您在客户端将数据插入数据集中,我发现它在那里占用内存是很自然的。您有一个长度至少为 1000 的字符串字段,乘以 200000 条记录。如果您不需要客户端上的这些数据,您可以查看executing commands in FireDAC

标签: sqlite delphi firedac


【解决方案1】:

TFDTable 是一个围绕查询对象的瘦包装器,它可以构建 SQL 命令来操作底层 DBMS 表。它有自己的存储(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;

【讨论】:

    猜你喜欢
    • 2010-12-26
    • 1970-01-01
    • 2016-05-04
    • 1970-01-01
    • 2012-03-28
    • 2018-05-08
    • 2016-06-21
    • 2011-02-16
    • 1970-01-01
    相关资源
    最近更新 更多