Недостаточно памяти при вставке записей в SQLite, FireDac, Delphi

У меня есть приложение Delphi, которое вставляет около 200000 записей (около 1 ГБ) в базу данных SQLite через компонент FireDac TFDTable. Когда он вставляется, я вижу, как увеличивается объем памяти приложения, пока не появится сообщение об ошибке "Недостаточно памяти". Я предполагаю, что это связано с кешем и подкачкой страниц, но я не могу найти ничего, что могло бы исправить закрытие и повторное открытие базы данных каждые 1000 записей или около того. Мысли?

Отредактировано... Извините за тонко сформулированный вопрос... Код был прост, поэтому я не включил его, но выглядит в основном так:

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

Теперь я ожидаю, что объем памяти может увеличиться, поскольку строка, вероятно, копируется в кэш-память БД. Если я посмотрю на распределение с помощью GetMemoryManagerState(), то смогу увидеть это. Я ожидаю, что в какой-то момент память в кеше будет сброшена при записи данных на диск. Однако, похоже, что нет. Это продолжается до тех пор, пока я не получу ошибку "Недостаточно памяти".

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

Я знаю, что здесь не так много. Но я не думал, что это тоже не получится, и я надеялся, что у кого-то может быть похожая проблема.

1 ответ

Решение

TFDTable - это тонкая оболочка вокруг объекта запроса, которая может создавать команды SQL для работы с базовой таблицей СУБД. У него есть собственное хранилище (объект Table), в котором хранятся данные, извлеченные клиенту, а также вставленные вами кортежи. Но все, что находится в памяти, не имеет основного файлового кэша.

Хотя это внутреннее хранилище может быть очищено во время вставки, TFDTable не является хорошим объектом для вставки данных в таком количестве. Лучше использовать объект запроса, такой как TFDQuery, который в сочетании с техникой выполнения пакетных команд, называемой Array DML, может принести вам реальное повышение производительности даже для локального механизма СУБД. И 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;
Другие вопросы по тегам