Вставка большого объекта в Postgresql возвращает ошибку 53200 Out of Memory

PostgreSQL 9.1 NPGSQL 2.0.12

У меня есть двоичные данные, которые я хочу сохранить в базе данных postgresql. Большинство файлов загружаются нормально, однако большой двоичный файл (664 Мб) вызывает проблемы. При попытке загрузить файл в postgresql с использованием поддержки больших объектов через Npgsql сервер postgresql возвращает ошибку «недостаточно памяти».

В настоящее время я запускаю это на рабочей станции с 4 ГБ ОЗУ, из которых 2 ГБ свободно, а postgresql работает в режиме ожидания.

Это код, который я использую, адаптированный из Руководство пользователя PG Foundry Npgsql .

using (var transaction = connection.BeginTransaction())
{
    try
    {
        var manager = new NpgsqlTypes.LargeObjectManager(connection);
        var noid = manager.Create(NpgsqlTypes.LargeObjectManager.READWRITE);
        var lo = manager.Open(noid, NpgsqlTypes.LargeObjectManager.READWRITE);
        lo.Write(BinaryData);
        lo.Close();
        transaction.Commit();
        return noid;
    }
    catch
    {
        transaction.Rollback();
        throw;
    }
}

Я попытался изменить настройки памяти postgresql со значений по умолчанию на всевозможные настройки значений:

  • общие_буферы
  • work_mem
  • Maintenance_work_mem

До сих пор я находил postgresql отличной системой баз данных, но в настоящее время это не работает, и я не могу поместить файл такого размера в базу данных. Я действительно не хочу иметь дело с ручным разрезанием файла на куски и воссозданием клиентской части, если я могу помочь.

Пожалуйста помоги!?


person Jayden    schedule 24.01.2013    source источник


Ответы (2)


Я думаю, что ответ заключается в итеративном вызове метода Write() класса LargeObject с фрагментами массива байтов. Я знаю, что сказал, что не хочу иметь дело с разбиением данных на фрагменты, но на самом деле я имел в виду разбиение данных на отдельные LargeObjects. Это решение означает, что я разбиваю массив на части, но он по-прежнему хранится в базе данных как один объект, то есть мне не нужно отслеживать части файла, а только один oid.

 do 
 {
   var length = 1000;
   if (i + length > BinaryData.Length) length = BinaryData.Length - i;
   byte[] chunk = new byte[length];
   Array.Copy(BinaryData, i, chunk, 0, length);
   lo.Write(chunk, 0, length);
   i += length;
 } (i < BinaryData.Length)
person Jayden    schedule 24.01.2013

Попробуйте уменьшить количество max_connections, чтобы зарезервировать память для нескольких подключений, которым необходимо выполнить одну операцию размером 700 МБ. Увеличьте work_mem (память, доступная для каждой операции) до 1 ГБ. Попытка втиснуть 700 МБ в одно поле звучит странно.

Увеличьте размер shared_buffers до 4096 МБ.

person Eric Leschinski    schedule 24.01.2013
comment
Уменьшено max_connections = 4 (postgresql не будет запускаться с меньшим количеством). Без изменений. Увеличено shared_buffers=1000MB (postgresql не будет запускаться с более высоким значением). Без изменений. Эти данные хранят файлы (двоичные данные). Я пытаюсь сохранить особенно большой файл. - person Jayden; 25.01.2013