2009-07-23 3 views
2

Каков ваш совет по настройке PostgreSQL, чтобы BLOB можно было быстро написать?Как быстро вставить BLOB в PostgreSQL?

Мы используем PostgreSQL для ввода BLOB с высокой скоростью.

  1. Мы называем lo_write() примерно 220 раз в секунду.
  2. Мы пишем примерно 30 Кбайт двоичных данных за lo_write().
  3. Это эквивалентно примерно 6 Мбайт/с.

Наш компьютер - RAID-5, поэтому скорость записи составляет около 200 МБ/с.

Мы уже настроили postgresql.conf иметь следующее:

  1. мы изменили shared_buffers = 1GB
  2. мы выключили FSYNC
  3. logging_collector = выкл (в значительной степени все, что связано с Протоколирование выключено)

Мы убедились, что если мы не храним BLOB как часть нашего запроса INSERT, то PgSql будет поддерживать штраф. Только когда мы храним BLOB как часть нашего запроса, он замедляется.

EDIT: Я использую Windows XP/Server. Я использую Pgsql 8.3 с PostGIS 1.3.6. Причина, по которой мне нужно было хранить BLOB в БД, - это то, что мое приложение требует от меня поиска этих BLOB в режиме реального времени.

Основание: Наше приложение представляет собой высокоэффективную обработку сигналов в реальном времени, где мы храним наши сигналы в базе данных как BLOB.

EDIT: Это код на C++, который использовался для выполнения теста. По-видимому, мы получаем около 16 МБ/с в нашей конфигурации RAID.

#include "libpq-fe.h" 
#include "libpq/libpq-fs.h" 
#include <sstream> 
#include <iostream> 
#include <tbb/tick_count.h> 

void test() 
{ 
    std::stringstream stst; 
    stst << "user=postgres password=1234 dbname=test_db"; 
    PGconn* conn = PQconnectdb(stst.str().c_str()); 
    if (PQstatus(conn) != CONNECTION_OK) 
    { 
    throw std::exception("failed to connect To DB engine: "); 
    } 

    const int dataSize = 18512; 
    char* data = (char*) malloc(dataSize); 


    const int count = 10000; 

    tbb::tick_count t0 = tbb::tick_count::now(); 
    for(int idx = 0; idx < count; idx++) 
    { 
    // Insert acoustic binary into large object table "pg_largeobject" 
    Oid objectId; 
    int lobj_fd; 
    PGresult *res; 

    res = PQexec(conn, "begin"); 
    PQclear(res); 

    objectId = lo_creat(conn, INV_READ|INV_WRITE); 
    if (objectId == 0) 
    { 
     throw std::exception("AddAcousticTable: Cannot create large object\n"); 
    } 

    lobj_fd = lo_open(conn, objectId, INV_WRITE); 

    const unsigned int writeBytes = lo_write(conn, lobj_fd, data, dataSize); 
    if (writeBytes != dataSize) 
    { 
     std::stringstream msg; 
     msg << "PsSasDataDB::AddToAcousticTable(): Incorrect number of bytes written for large object "; 
     msg << writeBytes; 
     throw std::exception(msg.str().c_str()); 
    } 

    lo_close(conn, lobj_fd); 

    res = PQexec(conn, "end"); 
    PQclear(res); 
    } 
    tbb::tick_count t1 = tbb::tick_count::now(); 

    std::cout << "Performance: " << (double(count*dataSize)/(t1-t0).seconds())/(1024.0*1024.0) << " MB/seconds"; 

    free(data); 
} 
int main() 
{ 
    try 
    { 
    test(); 
    } 
    catch(std::exception e) 
    { 
    std::cerr << e.what(); 
    } 

    return 0; 
} 
+0

Какие версии (OS и PG)? Почему вы выбрали крупные объекты? По-видимому, консенсус заключается в том, что просто хранение файлов в файловой системе работает лучше, если у вас нет разумного основания использовать BLOB-базы данных. – kquinn

+0

Я отредактировал вопрос, чтобы предоставить ответы на ваши комментарии. Благодарю. – sivabudh

+0

Если вы могли бы опубликовать достаточно вашей схемы базы данных, что пример кода будет работать против этого подмножества, это позволит другим людям запустить ваш тест и получить гораздо лучшие данные. Просто наличие кода на C++ без возможности попробовать запустить это не так полезно. –

ответ

4

RAID5:

Он отлично подходит для чтения, для записи много больших объемов данных, а также для стоимости. Это отстой для мелких случайных записей.

Поскольку вы, вероятно, не используете свою БД для хранения ТОЛЬКО больших блобов, вы также можете записывать/обновлять/вставлять базы данных, RAID5 будет настоящей PITA.

  • ВСТАВЬТЕ ИЛИ ОБНОВЛЯЙТЕ строку в таблице. -> страница в таблице должна быть записана -> для каждого индекса необходимо обновить хотя бы одну страницу индекса -> при фиксации журнал должен быть записан, сброшен на диск и синхронизирован.

Каждые из этих малых 1 страницы (8kB) пишет меньше, чем размер RAID5 полосы, так что контроллер RAID нужен будет искать несколько (или все) из ваших RAID дисков, прочитать несколько полос, и переписать обновленная полоса и четность. Для синхронизации вы должны ждать, пока ВСЕ диски будут синхронизированы, в течение которых они не обслуживают никаких других запросов ...некоторые RAID-контроллеры также особенно плохо работают при этом быстро, это зависит от вашего оборудования.

-> для высокой случайной пропускной способности записи, рекомендуется использовать RAID 1 (или 10 или 01) для данных и дополнительный том RAID1 для входа на 2 отдельных диска.

Итак, если у вас в вашем RAID-массиве 3 диска, удалите их, поместите данные на диск и войдите в систему на другом, а также в качестве теста. Если это хорошо, добавьте дополнительный диск и сделайте 2x тома RAID1 (журнал, данные).

Если ваша загрузка была тяжелой для чтения, а не тяжелой для записи, для того же бюджета (количество дисков) было бы лучше разместить журнал на том же томе, что и данные и RAID10.


Причина, почему я должен хранить BLOB в БД, потому что мое приложение требует от меня, чтобы искать эти BLOB-в режиме реального времени.

Вы положили BLOB-в базе данных, если вы хотите использовать материал, что база данных делает хорошо (например, транзакции, безопасность, или положить все на 1 сервер доступен из любого места, когерентные резервных копий, не головной боли и т.д.).

Если вы хотите выполнять поиск, вы не используете BLOB для поиска, вы используете простые таблицы базы данных и SQL-запросы для получения ссылки на BLOB, который вы хотите. Затем вы получаете BLOB, но вместо этого вы можете легко получить файл файловой системы. Таким образом, в вашем приложении вы могли бы, вероятно, использовать файлы файловой системы, а это было бы намного быстрее.

+0

путем хранения двоичных данных на диск, не удаляются ли данные из базы данных, что может привести к проблемам с обслуживанием? то есть, когда выполняется резервное копирование, если файл потерян и т. д. ... тогда мы не смогли бы получить этот файл. что вы думаете? – sivabudh

+0

Кому это важно, если данные «разделены»? Просто убедитесь, что вы создаете резервную копию любой директории, в которой вы даете свои данные; если у вас уже есть сплоченная система резервного копирования, добавление еще одного каталога к ней должно быть очень простым. BLOB обычно больше проблем, чем они того стоят, и использование файловой системы для них вместо базы данных должно сделать много вещей * намного проще. – kquinn

+0

, где у вас может возникнуть проблема с резервными копиями, является постоянство ... говорят, что вы создаете резервные копии файлов, а затем БД, но пользователь добавил файл одновременно, поэтому он находится в БД, но резервная копия файла пропустила его ... решение заключается в резервном копировании базы данных сначала, а затем в файлы. Кроме того, только COMMIT запись БД после записи файлов файловой системы и удалите файл после COMMITing удаления из БД. Если сбой INSERT вы можете получить файлы без записей БД (не проблема: поскольку вставка не удалась, приложение знает, что это не удалось), но вам нужно какое-то еженедельное задание cron, чтобы проверить его и очистить (или нет). – peufeu

1

Не сдавайтесь на RAID5. Современные RAID-системы могут дать вам 300-350 Мбайт/с в RAID-5 или RAID-6.

Я также использовал pg_largeobject для хранения файлов. Это только привело к резервным копиям и головным болям OID, хотя это был PostgreSQL 7.2/7.3.

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

+0

То, что вы можете получить 300+ МБ/с последовательной производительности, не имеет значения, когда проблемы с RAID5 связаны с его случайной производительностью. –

2

Самая большая победа для увеличения производительности записи на стороне базы данных задала контрольные точки на гораздо большее число. Значение по умолчанию - 3, вы хотите 30 или более минимум. Журналы базы данных в вашей системе, вероятно, заполняются предупреждениями об этом, если вы посмотрите на них.

Помимо этого, получение хорошей производительности записи превращается в проблему с аппаратным диском, чем что-либо еще. Какой RAID-контроллер вы используете? Оптимизирован ли он с использованием кэша записи с резервной батареей? Это самая важная вещь, которую нужно сделать правильно - если вы это сделаете, RAID5 может быть терпимым к подобной ситуации, потому что кэш контроллера будет объединяться с некоторыми случайными записями.

P.S. Не выключайте fsync, это опасно. Вместо этого вы должны использовать asynchronous commit, который выполняет ту же базовую функцию (сокращает количество дисковых флешей), но гораздо безопаснее.

1

Больше аппаратного ответа, чем программное обеспечение одного, но:

Это походит на фантастическое использование для RAM-диска или SSD, чтобы ослабить давление произвольного доступа на RAID5.RAM-диск, только если вы можете терпеть потери данных (или от батареи), конечно, и многоуровневые SAN с использованием SSD невидимо дороже обычных SAN, но в Solaris это можно сделать в ZFS, и есть некоторые незрелые Клоны Linux. Вы смотрите на ускорение порядка по сравнению с прямыми случайными записями.

Рассмотрите также возможность обновления прошивки к контроллеру SAN и/или обновление внутренней памяти, поддерживаемой батареей. Если он достаточно велик, он обычно может писать более эффективно, что повышает вашу пропускную способность.

1

Я столкнулся с той же проблемой и выполнил сравнительный тест между двумя вариантами: сохранение данных blob в файлах или в байтах в базе данных.

Я сконфигурировал столбец для использования ВНЕШНЕГО режима хранения (режим TOAST).

Тест состоял из отправки клиентом 1000 серых изображений, каждый из которых 326 * 244 пикселей (всего 636 Мбит) и хранения их сервером.

Каждый тест повторяли 5 раз. Результаты показывают, что средняя скорость передачи данных обрабатывается в каждом методе в Мбит/с.

Файлы: 119,9 DB: 164,8

Удивительно, сохранение изображений в базе данных 37% быстрее в течение хранения в файлах! Я думаю, что открытие и закрытие сотен файлов является узким местом при использовании стандартной файловой системы.

я выполнил тест на x86 Windows 7 32 бит, сервер 4 Гб (то есть, мой ноутбук ...) работает PostgreSQL 9.2

+0

Очень интересный результат. Надеюсь, вы не отключили fsync? Если ваши изображения сжимаемы, их можно частично отнести к автоматическому сжатию TOAST – mvp

Смежные вопросы