Пути более эффективного использования PostgreSQL

Прочитав статью Базы данных в онлайн играх и особенно комменты к ней, я в очередной расстроился от мысли, что многие разработчики меняют БД в своём проекте, пытаясь этой сменой решить свои проблемы, не исчерпав, однако, всех возможностей, предоставляемой заменяемой БД. Я принимаю участие в работе над проектом, БД которого характеризуется:
  • Количеством транзакций порядка 5'000 — 10'000 в секунду
  • Объемом примерно в 100ГБ (который бодро растёт)
  • Примерно равным количеством операций на чтение/запись
  • Преимущественно мелкими транзакциями

В силу, как говорится, исторических причин, вся база представляет из себя, гхм, одну базу, пока без шардинга, который мог бы решить ряд проблем. Тем острее стоит вопрос о поиске решений, заключённых именно в особенностях PostgreSQL. Решений, которые можно реализовать малой кровью.

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

Речь пойдёт о PostgreSQL 9.2 (9.3 еще не щупали). И, да, здесь не будет админских советов по оптимальной настройке конфигов — я бы сам рад был узнать, как правильно их точить.

Капитанские рекомендации вроде «создавайте правильные индексы» тоже будут отсутствовать. Предполагаю, что эти нанотехнологии лежат на поверхности.

Большие размеры таблиц и индексов


Не секрет, что чем интенсивнее производится запись в БД, тем быстрее уменьшается в среднем скорость выборок и база начинает «тупить». Связано это напрямую с транзакционной сущностью БД. Поскольку строки (кортежи) имеют версионность, при изменении значения в некой строке это значение нельзя просто так взять и записать вместо предыдущего. PostgreSQL вместо этого дублирует строку и её новый, изменённый вариант записывает отдельно. Т.е., грубо, если взять таблицу в 1ГБ и единой операцией сделать UPDATE любому полю, то таблица «внезапно» увеличится в размере до 2ГБ. То же самое примерно происходит и с индексами. Увеличение размеров БД сразу сказывается и на скорости выполнения запросов.

Разумеется, регулярно будет работать AUTOVACUUM (если настроен), ну или можно запускать руками VACUUM по мере необходимости.

Что можно сделать для смягчения проблемы?

  • Использовать fill factor. Этот параметр определяет степень заполненности страниц (блоков данных) таблиц на диске и то, сколько нужно оставить свободного места в блоках для записи туда изменённых версий кортежей. Наш опыт (обновления, в основном, по одной записи, но много) показывает, что для получения заметного положительного эффекта достаточно значения 90% (по умолчанию он равен 100%, т.е. таблица максимально плотно упакована). Это означает, что таблица будет заведомо больше как минимум примерно на 10%, зато при апдейте строк их новая версия может быть записана не абы куда, а в тот блок, в котором и находилась, что и быстрее, и компактнее. Документация упоминает, что для таблиц, в которых записи не изменяются никогда (или крайне редко), смысла менять fill factor нет, что есть правильно. Кстати, для индексов fill factor уже по умолчанию равен 90.
  • Использовать частичные индексы (partial indexes). Зачастую может оказаться, что вас в выборках интересуют только записи с определенным значением булевого поля или определённого значения перечисления (enum). Например, вы в базе организовали хранение тасков для выполнения фоновых задач (что, правда, не лучшая идея, но уже по другим причинам) и чаще всего выбираете оттуда таски со статусам «new». Так зачем индексировать всю таблицу, если фактически выборка производится из ничтожно малого количества записей (явно новых тасков будет сильно меньше, чем уже завершённых)? Установка ограничения на индекс уменьшит его размеры в разы, если не на порядки.
  • Использовать функциональные индексы (functional indexes). Функциональные индексы — мощный инструмент, который вообще может позволить избежать создания некоторых колонок в таблице. Например, есть в таблице поле типа timestamp с датой и временем. И нужно часто делать выборки, положим, с выборкой данных по часам. Можно выполнять поиск прямо по колонке timestamp (и повесить на неё индекс). Можно создать отдельную колонку, куда по триггеру или руками сохранять отдельно значение часа. А можно создать функциональный индекс, который будет содержать только значения часов и строиться на основе уже имеющейся колонки timestamp. В результате и колонок лишних не создали, и индекс эффективный есть.

Медленные выборки


  • Не теряют своей актуальности два предыдущих пункта — использование частичных и функциональных индексов.
  • Кластеризация (CLUSTER). Полезная тема, если вы знаете типовые варианты обращения к своим объектам. В процессе кластеризации таблиц по указанному индексу PostgreSQL распределяет данные таблицы на жёстком диске упорядоченно, в соответствии с индексом. К примеру, есть таблица со списком квартир, привязанных к домам. Можно создать индекс по полю «id дома» и произвести по нему кластеризацию, в результате записи о квартирах будут физически сгруппированы по домам и при запросах вида «верни мне все квартиры дома №777» базе уже не потребуется собирать квартиры по всей таблице. Они будут храниться компактно. Правда, кластеризацию надо регулярно повторять. В процессе AUTOVACUUM она не производится.

Превышение счётчика транзакций


Работа механизмов MVCC была бы невозможна без существования счётчика транзакций. Загадка, почему до сих пор счётчик этот 32-х битный, но имеем то, что имеем — через каждые 2 миллиарда с хвостом транзакций счётчику полагается обнулиться. А для того, чтобы не произошло непоправимое, к этому моменту должны обнулиться номера транзакций у всех строк в БД. Точнее, этим строкам ставится в соответствие некий зарезервированный FrozenXID. Что характерно, AUTOVACUUM и ручной VACUUM не занимаются простановкой FrozenXID и для нормальной работы БД при достижении счётчиком транзакций определённого конфигом значения запускается автовакуум с красивым комментом «to prevent wraparound». При больших таблицах (в десятки ГБ) этот процесс может занять томительные часы, в течение которых таблица будет недоступна ни для чтения, ни для записи.

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

Длинные транзакции


Это достаточно очевидно, но на всякий случай упомяну.

Речь идёт не о длинных транзакциях как таковых, а о ситуациях, когда приложение из-за бага не закрыло транзакцию и ушло делать свои дела дальше (к примеру, фоновые обработчики задач, способные висеть сутками). В списке активных процессов PostgreSQL такое соединение будет висеть со статусом «idle in transaction». Регулярно отрабатывающий VACUUM освобождает место, занятое старыми версиями строк (оставшимися после редактирования или удаления), ориентируясь по номеру транзакции, в которой было произведено удаление или редактирование. Грубо говоря, если были строки, удалённые транзакциями 1 и 2, а минимальный номер среди текущих открытых транзакций — 3, то эти две строки можно удалить «по-настоящему», т.к. они не попадают в область видимости любой текущей открытой транзакции. В случае подвисшей транзакции VACUUM не сможет удалить ни одну строку, отредактированную после запуска этой транзакции, в результате чего база за несколько часов может чудовищно вырасти.

Совет тут один — мониторить текущие процессы и отлавливать негодяев с «idle in transaction».

Длительные блокирующие бекапы


Репликации, при всей своей привлекательности, не спасают от ситуаций, когда база была побита, к примеру, кривым патчем. Сделали патч по какой-нибудь там перелинковке объектов, всё добро среплицировалось — и привет. Поэтому бекапы, как ни крути, нужны. Большая база бекапится у нас около часа. Практически всё это время проект бездействует. Тут, откровенно говоря, посоветовать ничего не могу. Наоборот, буду рад выслушать, кто и как с ситуацией справляется. Единственная мысль — бить на шарды и бекапить кусками, думая, как при этом сохранить консистентность данных.

В версии 9.3 произведена заметная работа над представлениями, которые тоже могут позволить оптимизировать работу с БД, но это уже отдельная тема.
Поделиться публикацией

Комментарии 55

    +8
    Вспомнил один хороший рецепт для PG.
    Как известно, для регистронезависимого поиска в PG есть ILIKE. Ещё известно, что он значительно медленнее, чем просто LIKE.

    Я в своё время нашёл вот такой рецепт:
    Очевидная часть рецепта: Поле по которому осуществляется поиск надо обязательно проиндектировать.
    Не очень очевидная часть рецепта:
    1) В индексе установить operator class = text_pattern_ops
    2) Сделать индекс функциональным LOWER/UPPER(text)
    3) Осуществлять поиск при помощи LIKE LOWER/UPPER(text)

    У нас при работе с КЛАДРом скорость выборки выросла раз в 10, по сравнению с голым ILIKE и обычным индексом с настройками по-дефолту.
      +2
      Интересно. Если будет время, попробую провести и опубликовать тесты по вашему рецепту и тому, что сам написал. С тестами то оно нагляднее будет.
        0
        Ещё иногда спасает изменение «поведения функции» (не знаю как это точно называется) IMMUTABLE | STABLE | VOLATILE. По умолчанию все функции VOLATILE, что является самым надёжных/безопасным поведением с точки зрения отстреливания себе конечностей. Но в циклах VOLATILE очень медленный.

        Как правило, если функция не изменяет данные, а только читает их и не выполняется в циклах вместе с попутным изменением данных, то можно смело ставить IMMUTABLE и функция будет выполнятся только один раз при первом обращении в цикле, далее значение «закэшируется» и повторный вызов функции вернёт значение из «кэша». Тоже позволяло в некоторых случаях уменьшить время выполнения запросов.

        P.S.: А у меня появилось желание пощупать «fill factor» =)
          +1
          С fill factor может получиться интересно, но там результат вроде как сильно зависит от характера обновлений/удаления записей. Если обновлять записи большими пачками, то никакого fill factor'а не хватит ). Аналогично, если запись идёт в множество потоков, может потребоваться ставить значение и пониже, до 80 — 70. С другой стороны, размер БД гарантированно возрастает и стоит ли овчинка выделки — с каждой таблицей нужно смотреть, как обычно, отдельно. В общем, всё туда же — надо тесты погонять )
            0
            fill_factor работает только если размер «запаса» превышает размер измененой части таблицы между двумя итерациями автовакума для нее.

            Даже немного не так… В «правильной ситуации» размер update между автовакумами должен быть некой постоянной величиной… Например у вас между автовакумами обновляется обычно 10% таблицы. Т.е. в нормальном состоянии у вас 10% файла — дырки в которые нельзя писать, просто потому что FSM про них не знает. Поэтому писаться новые будут — увеличивая файл. fill_factor позволяет создать некий запас в который будут помещаться записи, пока FSM прочухает.

            +2
            Немного не так. IMMUTABLE можно ставить если значение зависит только от аргумента, а не от данных бд. Она сама не будет выполнять никаких запросов в БД. Она выполняется вообще один раз как только вычислен параметр а если он не зависит от данных БД, то вообще посчитается на этапе планирования запроса.

            STABLE — значение зависит от данных в БД, но при последовательных проходах по одним и тем же данным будет возвращать один результат. Соответственно ее можно закешировать, и сделать что то вроде временной таблички.
              0
              Память меня подвела) спасибо, что поправили.
              Только есть один момент, если в IMMUTABLE функцию поместить SELECT, то он же сделает выборку из таблицы, разве не так? Т.е. не обязательно, чтобы функция не работала с данными БД вообще.
        –1
        По поводу первого пункта «Большие размеры таблиц и индексов» и постгресовской реализации MVCC.

        Перечисленые вами пункты «для смягчения проблемы» имо очень незначительно смягчают ее и эти рекомендации скорее касаются «администраторов» БД, а не разработчиков.
        В целом MVCC придуман, чтобы мы не заморачивались с блокировками, dirty read и т.д. Оно очень облегчает жизнь, но имеет кучу недостатков, включая описаную вами проблему с ростом размера таблицы и постоянным VACUUM, который кстати тоже не делает все это хозяйство быстрее (т.к. VACUUM — операция блокирующая, даже хуже read-write-блокирующая).

        Я это к тому, что как-только разработчик получает от MVCC больше проблем, чем приимуществ (в том числе и падающая performance) ему стоит внимательнейшим образом почитать следующую главу в документации:
        PostgreSQL: Documentation: Explicit Locking.
        Просто настоятельно рекомендую. Это конечно не MVCC и нужно понимать что делаешь (например можно огрести неслабые deadlock), но при правильном применении, это не просто «смягчает» проблему с реально большими данными — это иногда позволяет просто в разы ускорить некоторые операции.
        Особенно интересно и с точки зрения performance наиболее продуктивно использование «advisory locks».
          +2
          VACUUM — операция блокирующая, даже хуже read-write-блокирующая

          Да что вы:
          Plain VACUUM (without FULL) simply reclaims space and makes it available for re-use. This form of the command can operate in parallel with normal reading and writing of the table, as an exclusive lock is not obtained.
            –1
            Те записи, которые перетаскиваются, имеют row lock. Что к сожалению при использовании индексов, те которые влияют на join или sort выборку, т.е. даже напрямую не затронутые vacuum, но стоящие после них, тоже приводит к блокировкам.
            Приведенная вами цитата имеет ввиду, что не осуществляется table lock.
              +1
              VACUUM не перетаскивает ничего, он удаленные строки (которые уже гарантированно никому не нужны) окончательно удаляет
                –1
                Ну да, поэтому после vacuum (не FULL) иногда размер таблицы в несколько раз меньше…
                Индексы, особенно GINы, перестраиваются полностью, кластеры удаляются иногда целыми кусками.
                Про FULL я вообще молчу…
                  +2
                  Нет. Вы не правы.

                  Обычный вакум не перетаскивает строки. Обычный вакуум может только «подрезать» файл таблицы с конца если все записи в конце файла помеченны как удаленные. Особенно это начинает работать если fill_factor не 100% и все новые записи у вас «месятся» в начале файла. Старые оказываются в конце файла. Индексы как раз не перестраиваются и в этом преимущество обычного вакуума над FULL. У вас в индексе по прежнему все записи показывают на теже смещения в исходном файле таблицы. А вот когда работает FULL то он перемещает строки и индексы «распухают». Поэтому после full стоит делать REINDEX.

                  Вакуум обычный иногда требует краткосрочный TABLE LOCK или ROW LOCK для того чтобы поменять метаинформацию по файлу таблицы.

                  Вообщем про это достаточно подробно рассказывал Брюс Момджан на HL++ 2013 www.highload.ru/2012/abstracts/410.html про вакуум начинается с 44 слайда.
                    0
                    *2012
                      0
                      Особенно это начинает работать если fill_factor не 100% и все новые записи у вас «месятся» в начале файла.

                      Именно в начале файла или в свободной зоне, определяемой значением fill factor?
                        0
                        скорее в «начале файла» в том смысле что чем ближе к началу тем лучше. Т.е. когда у вас запись апдейтиться лежавшая в конце файла то ее новая версия ляжет ближе к началу. Очевидно что чем больше «свободное место fill_factor» тем больше шансов что оно окажется ближе к началу файла.

                        Почему работает «уже 90%» потому что обновляется менее чем 10% базы данных при апдейтах за интервал между автовакуумами. Если у вас апдейты будут менять сразу полтаблицы то конечно от филфактора будет немного проку.
            +2
            Большая база бекапится у нас около часа. Практически всё это время проект бездействует. Тут, откровенно говоря, посоветовать ничего не могу. Наоборот, буду рад выслушать, кто и как с ситуацией справляется. Единственная мысль — бить на шарды и бекапить кусками, думая, как при этом сохранить консистентность данных.

            А почему бездействует? Простой бекап на уровне файловой системы не требует остановки базы:
            Perform the backup, using any convenient file-system-backup tool such as tar or cpio (not pg_dump or pg_dumpall). It is neither necessary nor desirable to stop normal operation of the database while you do this.

            www.postgresql.org/docs/9.2/static/continuous-archiving.html#BACKUP-BASE-BACKUP
              –3
              Цитата из PostgreSQL: Documentation: File System Level Backup:
              There are two restrictions, however, which make this method impractical, or at least inferior to the pg_dump method:
              • The database server must be shut down in order to get a usable backup. Half-way measures such as disallowing all connections will not work (in part because tar and similar tools do not take an atomic snapshot of the state of the file system, but also because of internal buffering within the server). Information about stopping the server can be found in Section 17.5. Needless to say, you also need to shut down the server before restoring the data.
              • If you have dug into the details of the file system layout of the database, you might be tempted to try to back up or restore only certain individual tables or databases from their respective files or directories. This will not work because the information contained in these files is not usable without the commit log files, pg_clog/*, which contain the commit status of all transactions. A table file is only usable with this information. Of course it is also impossible to restore only a table and the associated pg_clog data because that would render all other tables in the database cluster useless. So file system backups only work for complete backup and restoration of an entire database cluster.

              А вообще, видел уже бэкапы, сделаные как вы написали, которые потом никакими средствами не хотели больше заводится.
                +2
                Прошу прощения, я имел в виду конкретно такой метод бекапа (с WAL архивацией):
                www.postgresql.org/docs/9.2/static/continuous-archiving.html#BACKUP-LOWLEVEL-BASE-BACKUP
                  –2
                  Ну вообще делать бекап на уровне файловой системы — моветон. Хотя репликация в постгрессе, учитывая исторические корни тоже получается моветоном… Но обычный pgdump ничего не лочит и транзакционен. правда в случае чего вы потеряете все данные начиная с момента начала дампа.
                    0
                    В нашем случае он может и не лочит, но обеспечивает такую нагрузку на БД, что состояние практически эквивалентно простою проекта, хоть какие-то операции может быть и проходят :)
                    правда в случае чего вы потеряете все данные начиная с момента начала дампа.

                    Поясните, пожалуйста, этот момент. Работает БД, начинаем делать бекап. Бекап обламывается (хех, место на диске закончилось, было). Получаем битые бекап (можно сделать снова) и целую нормальную базу. Или я что-то не понял, или потерь нет.
                      0
                      Речь идет о том, что в бекап попадут только данные, которые были в базе на момент старта дампа.
                        0
                        А, ну это понятно. Я бы не стал называть это потерями :)
                          0
                          правильный бекап это инкрементальный. Типо пока дампим всю базу… потом дампим дельту что за это время пришла… потом еще чуть чуть… и практически к у нас получается что к окончанию бекапа мы видим базу на момент окончания бекапа и начинаем следующий :)
                      +3
                      Почему сразу моветон, абсолютно нормальный метод, MVCC тому способствует.
                      Разумеется, надо не втупую архивировать живую базу, а сначала запустить pg_start_backup('label');

                      Заодно нагрузку на чтение можно контролировать напрямую, через пайп-тротлинг например.
                        0
                        а сначала запустить pg_start_backup('label');
                        И на реально больших базах ждать ждать ..., пока он покроет чек-пойнтами базу.
                          +1
                          Но работать же не мешает. Подождать, пока закончится pg_start_backup — всяко лучше, чем ложить весь сервер чтобы получить дамп.
                            0
                            А чем вас WAL-то не устраивает?
                              0
                              ну дефакто это работа с внутренним бинарным механизма БД, в опять таки бинарном формате. И где гарантия хоть какой то обратной совместимости? В теории даже минорный апдейт билда сервера может сломать возможность восстановить БД. Это скорее не бекап, а некая реплика + HotStandBy. К сожалению репликация и бекапы у постгресса не настолько «взрослые» как, например, его SQL.
                                +1
                                > В теории даже минорный апдейт билда сервера может сломать возможность восстановить БД.

                                Минорный точно не сломает. Мажорные апдейты ломали совместимость до 9.3 (но гарантии нет, что опять будут менять). Но минорный на то и минорный, что только баг-фиксы (если что то ломается — например баг в тех же Wal-логах — будет писаться большими буквами в релизе)
                                0
                                Лично меня устраивает и pg_dump — база кешируется в ram и дампится быстро, а заархивированный дамп занимает минимум места.
                                WAL — тоже отличный метод, в частности, можно организовать слейв специально под бекап и снимать с него дамп через pg_dump не беспокоясь о нагрузке (только следить чтобы репликация сильно не отстала).
                    0
                    Поэтому бекапы, как ни крути, нужны. Большая база бекапится у нас около часа. Практически всё это время проект бездействует. Тут, откровенно говоря, посоветовать ничего не могу. Наоборот, буду рад выслушать, кто и как с ситуацией справляется. Единственная мысль — бить на шарды и бекапить кусками, думая, как при этом сохранить консистентность данных.

                    Используйте непрерывное резервное копирование. Если делать просто бэкапы — есть огромная возможность просто потерять данные за какое то время (ведь бэкапы делаются раз в N дней/недель). Мы использовали WAL-E и Barman. Обе утилиты отлично справляются. Восстанавливать можно до какого то лога или временной метки (если кто то запустил DELETE/TRUNCATE/DROP на весь кластер). Больше можно почитать тут.
                      0
                      Добавлю в копилку, может кому-то пригодится.

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

                      — таблицы пока что нельзя full vaccum-ить на ходу, но индексы можно. Нужно построить новый такой же (с другим именем, разумеется), и старый после этого удалить. Для неблокирующей постройки индекса нужно использовать опцию CONCURRENTLY.
                        +2
                        Мне кажется, однозначно ответить на вопрос, что лучше — разбивать большие апдейты или нет, может ответить только тот, кто знает логику работы конкретного приложения. В моём представлении, транзакции призваны обеспечить целостность записанных данных. Т.е., грубо говоря, если в моём приложении все, скажем, 10'000 записей должны или обновиться, или НЕ обновляться (а промежуточные варианты меня, допустим, не устраивают), я бы пихнул всё в одну транзакцию, хоть оно, типа, и нежелательно. Другое дело, что ситуаций с таким выбором лучше не допускать при продумывании архитектуры )
                          +1
                          Само собой, что, если вопрос стоит, что либо все, либо ничего, то надо использовать транзакции, в конце концов — они для этого и придуманы.
                          Просто в сети гуляют рекомендации, что много последовательных апдейтов стоит заключать в одну транзакцию, для того чтобы зря не нагружать индекс перестроениями. От таких рекомендаций в итоге больше вреда, чем пользы.
                            0
                            Я могу привести контр пример. При большом апдейте помечаются свободными целые страницы. Соответственно фрагментация уменьшается. Тут все спорно. Но опять последовательные апдейты в одной транзакции увеличивают шансы дедлока.
                            Лично я за апдейты вне транзакций если они логически не связаны. Хотя апдейты зло просто по факту своего наличия в версионнике.
                              +1
                              Насчет распухания таблиц при апдейтах в одной транзакции — не уверен. Мне кажется там скорее будет проблема из за длительной транзакции… Вот это реально огромное зло.
                          0
                          Рассматриваю возможность переход на Постгри с Мускула прежде всего из-за функциональных индексов (очень много сортировок по частям поля, по конкатенации, по кастингу и т. п.). Как они, не сильно тормозят на вставку по сравнению с обычными?
                            +1
                            Зависит от самого выражения (или функции). Например замеры создания индекса по lower(field) на поле 128 символов, не показали практически никакой разницы, чем то-же самое по такому же полю изначально в lower case. Вероятно просто относительно создания самого индекса временем исполнения lower можно принебречь.
                              +1
                              Скажу так — мы не упирались в тормоза функциональных индексов. И я как-то даже не вижу причин, почему они могут быть медленнее. Точных сравнительных тестов показать не могу — не делали.
                                +2
                                Сильно зависит от конкретного выражения. Но альтернатива ему — вычисление этого выражения на клиенте перед отправкой на вставку + поле в БД. Так что по суммарному CPU клиент+сервер разница врядли будет, а вот по нагрузке на диск будет точно.
                                Ибо это увеличение размера записи, следовательно чтение с диска почем зря, вымывание дискового кеша и замедление всех запросов даже для не связанных в этим полем вещей.

                                Вообще следует помнить что БД в первую очередь упираются в диск, во вторую в память и только потом уже CPU. Как правило современное серверное железо имеет излишек CPU с точки зрения БД.
                                  0
                                  Альтернатива может быть и типа t1 JOIN t2 ON LOWER(t1.name) = LOWER(t2.name). Ну и при относительно небольшой базе многое зависит от памяти и индексов: можем использовать индексы в запросах — получаем скачок производительности, помещаются часто используемые индексы в память — ещё скачок.
                              0
                              Позвольте, задам вопрос.
                              Стою перед выбором БД для задачи хранения текущих транзакций. Запросы примерно в таком порядке: insert, 5x update, delete. Select относительно редко и характерен для нештатных ситуаций — в нормальном случае транзакции хранятся в памяти приложений и из базы выгребаются либо на старте, либо при разгребании очереди. Никакой логики в БД (даже вероятно, без использования foreign key), только критически надежное хранение данных, размер записи низкий — до единиц килобайт, в таблице не более 100000 записей. Поток запросов — до 10000 в минуту, относительно низкий. Сам люблю psql, но в данном случае не уверен, что он будет лучшим выбором. nosql как-то для финансовых транзакций рассматриваю с опаской (возможно, стереотипы). Пока предварительно решил использовать mysql.
                              Что касается postgres, смущает vacuum, насколько помню, он может сильно подтормаживать выполнение текущих запросов в БД. Если я в чем-то заблуждаюсь, прошу меня поправить.
                              +3
                              Проблема с бекапами решается регулярными бекапами реплики (слейва).
                                0
                                Когда начнёте щупать 9.3, обратите внимание на новую опцию у pg_dump --jobs:
                                --jobs=njobs
                                Run the dump in parallel by dumping njobs tables simultaneously. This option reduces the time of the dump but it also increases the load on the database server. You can only use this option with the directory output format because this is the only output format where multiple processes can write their data at the same time.
                                  0
                                  Да, обращал. Также видел (сейчас, правда, найти сходу не смог) тесты, показывающие, что некий заметный прирост скорости дампа был только при двух потоках, а при трёх и более — уже несерьезно. Правда там уже, вероятно, всё в винты упирается.
                                  –3
                                  как такие тексты попадают на хабр и воообще в инет!?
                                  хабр, не позорься, нужна модерация!

                                  человек автар, почитай доку и сходи хотя бы на sql ru.

                                  Postgres — субд с более чем 10 летним уже опытом промышленного применения (это я взял от версии 7.4).
                                  Ваши 100ГБ при 10КTPS — да это смех!

                                  Михаил Тюрин
                                  DBA
                                  avito.ru
                                    +1
                                    Извините, Михаил, но я не понимаю зачем вообще такие комментарии тут нужны.
                                    Вы бы лучше по делу написали — посоветовали бы почитать что-то конкретное или сами выдали рекомендации.
                                    Я думаю хабр как раз для этого.
                                      0
                                      Я безмерно рад за вас, тёзка. И сожалею, что еще не обладаю вашим опытом.
                                      –1
                                      нда…

                                      вот о чем речь, по сути:

                                      «Описывайте симптомы проблемы, а не свои предположения»
                                      www.opennet.ru/docs/RUS/smart_question/
                                        0
                                        оставлю и я свои 5 копеек… бэкапы начиная с 9.1 можно делать через pg_basebackup это в разы удобнее чем pg_start/stop_backup+rsync. Очень и очень удобная вещь, к примеру выше есть коментарий, так вот есть такой ключ как -c fast и чекпоинт будет делаться asap, независимо от того что выставлено в checkpoint_timeout и checkpoint_completion_target. А в 9.4 уже есть коммит который реализует тротлинг… так что rsync будет не нужен)).
                                          0
                                          Вы так про версии расказываете, а легко в postgresql переходить с версии на версию (н-р 9.0 -> 9.2)? (чисто из практического интереса у нас 9.2 думаю в будущем обновить)
                                            0
                                            Да, довольно легко. Но тем не менее, зависит от того что внутри базы. Простой пример двухдневной давности, провел обновление с 8.4 на 9.3 с pg_upgrade. Обновление прошло гладко, а все потому что там не было ничего кастомного (специфические контрибы, репликации в виде slony/londiste, системы очередей типа pgqd). Вот, поэтому перед обновлением нужно обратить внимание на такие вещи и где-нибудь в сторонке развернуть бэкап и проиграть сценарий обновления.

                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                        Самое читаемое