Оптимизация PostgreSQL для быстрого тестирования

Я перехожу к PostgreSQL из SQLite для типичного приложения Rails.

Проблема в том, что запущенные спецификации стали медленными с PG.
На SQLite потребовалось ~ 34 секунды, на PG - ~ 76 секунд, что больше, чем 2x медленнее.

Итак, теперь я хочу применить некоторые методы к , чтобы обеспечить производительность спецификаций на уровне SQLite без изменений кода (в идеале, просто установив параметры подключения, что, вероятно, невозможно).

Несколько очевидных вещей с головы:

  • RAM Disk (хорошая настройка с RSpec на OSX была бы хорошей, чтобы видеть)
  • Unlogged tables (может ли он применяться ко всей базе данных, поэтому у меня нет изменений всех скриптов?)

Как вы, возможно, поняли, что меня не интересует надежность, а остальное (DB - всего лишь одноразовая вещь).
Мне нужно максимально использовать PG и сделать его настолько быстрым, насколько это возможно.

Лучший ответ идеально описывает трюки для этого, настройки и недостатки этих трюков.

UPDATE: fsync = off + full_page_writes = off уменьшено время до ~ 65 секунд (~ -16 секунд). Хорошее начало, но далеко от цели 34.

ОБНОВЛЕНИЕ 2: я попытался использовать RAM-диск, но прирост производительности был в пределах ошибки. Так что, похоже, не стоит того.

ОБНОВЛЕНИЕ 3: * Я нашел самое узкое место, и теперь мои спецификации работают так же быстро, как SQLite.

Проблема заключалась в очистке базы данных, которая выполняла усечение. По-видимому, SQLite слишком быстро там.

Чтобы "исправить", я открываю транзакцию перед каждым тестом и откатываю ее в конце.

Некоторые номера для ~ 700 тестов.

  • Усечение: SQLite - 34s, PG - 76s.
  • Транзакция: SQLite - 17s, PG - 18s.

2x увеличение скорости для SQLite. 4-кратное увеличение скорости для PG.

Ответ 1

Во-первых, всегда используйте последнюю версию PostgreSQL. Улучшения производительности всегда наступают, поэтому вы, вероятно, тратите свое время, если настраиваете старую версию. Например, PostgreSQL 9.2 значительно улучшает скорость TRUNCATE и, конечно же, добавляет только индексирование. Всегда следует соблюдать даже незначительные выпуски; см. в разделе политики .

Этикет

НЕ помещайте табличное пространство в RAMdisk или другое не долговременное хранилище.

Если вы потеряете табличное пространство, вся база данных может быть повреждена и сложна в использовании без существенной работы. Для этого очень мало преимуществ по сравнению с использованием таблиц UNLOGGED и в любом случае с большим количеством ОЗУ для кеша.

Если вам действительно нужна система на основе ramdisk, initdb новый кластер в ramdisk initdb с новым экземпляром PostgreSQL в ramdisk, поэтому у вас есть полностью одноразовый экземпляр PostgreSQL.

Конфигурация сервера PostgreSQL

При тестировании вы можете настроить сервер для не долговечной, но более быстрой работы.

Это одно из единственно приемлемых применений для параметра fsync=off в PostgreSQL. Этот параметр в значительной степени говорит PostgreSQL о том, что он не беспокоится о заказанной записи или какой-либо другой неприятной информации, защищающей целостность данных и безопасности при сбое, давая ему разрешение полностью уничтожать ваши данные, если вы потеряете питание или сбой ОС.

Излишне говорить, что вы никогда не должны включать fsync=off в производство, если вы не используете Pg в качестве временной базы данных для данных, которые вы можете повторно генерировать из других источников. Если и только если вы делаете, чтобы отключить fsync, вы можете отключить full_page_writes, так как это уже не так хорошо. Помните, что fsync=off и full_page_writes применяются на уровне кластера, поэтому они влияют на все базы данных в вашем экземпляре PostgreSQL.

Для использования в целях производства вы можете использовать synchronous_commit=off и установить commit_delay, так как вы получите много преимуществ, таких как fsync=off без риска гибели данных. У вас есть небольшое окно с потерей последних данных, если вы активируете асинхронное комментирование, но это оно.

Если у вас есть возможность слегка изменить DDL, вы также можете использовать таблицы UNLOGGED в Pg 9.1+, чтобы полностью исключить ведение журнала WAL и получить реальное ускорение скорости за счет стрижки таблиц, если сервер выйдет из строя. Не существует опции конфигурации, чтобы сделать все таблицы незаписанными, она должна быть установлена ​​во время CREATE TABLE. В дополнение к тому, чтобы быть хорошим для тестирования, это удобно, если у вас есть таблицы, заполненные сгенерированными или несущественными данными в базе данных, которые в остальном содержат вещи, которые вам нужны для безопасности.

Проверьте свои журналы и посмотрите, есть ли предупреждения о слишком большом количестве контрольных точек. Если да, вы должны увеличить checkpoint_segments. Вы также можете настроить свою контрольную точку_completion_target, чтобы сгладить записи.

Настройте shared_buffers, чтобы соответствовать вашей рабочей нагрузке. Это зависит от ОС, зависит от того, что еще происходит с вашей машиной, и требует некоторых проб и ошибок. По умолчанию они крайне консервативны. Возможно, вам потребуется увеличить ограничение максимальной общей памяти ОС, если вы увеличите shared_buffers на PostgreSQL 9.2 и ниже; 9.3 и выше изменили способ использования разделяемой памяти, чтобы избежать этого.

Если вы используете только пару подключений, которые выполняют большую работу, увеличьте work_mem, чтобы дать им больше оперативной памяти для сортировки и т.д. Остерегайтесь того, что слишком высокий параметр work_mem может привести к нарушению -memory, потому что он не сортируется для каждого соединения, поэтому один запрос может иметь много вложенных ролей. Вам действительно нужно увеличить work_mem, если вы можете увидеть сортировку, разливающуюся на диск в EXPLAIN, или войти в систему с параметром log_temp_files (рекомендуется), но более высокое значение может также позволить Pg выбрать более разумные планы.

Как сказал еще один плакат, целесообразно поместить xlog и основные таблицы/индексы на отдельные жесткие диски, если это возможно. Отдельные разделы довольно бессмысленны, вам действительно нужны отдельные диски. Это разделение имеет гораздо меньшую выгоду, если вы работаете с fsync=off и почти нет, если используете таблицы UNLOGGED.

Наконец, настройте свои запросы. Убедитесь, что ваши random_page_cost и seq_page_cost отражают производительность вашей системы, убедитесь, что ваш effective_cache_size верен и т.д. Используйте EXPLAIN (BUFFERS, ANALYZE) для просмотра отдельных планов запросов и включите модуль auto_explain, чтобы сообщать обо всех медленных запросах. Вы часто можете улучшить производительность запросов, просто создав соответствующий индекс или изменив параметры затрат.

AFAIK нет способа установить всю базу данных или кластер как UNLOGGED. Было бы интересно уметь это делать. Рассмотрите вопрос о списке рассылки PostgreSQL.

Настройка хост-системы

Там есть какая-то настройка, которую вы можете сделать и на уровне операционной системы. Главное, что вы, возможно, захотите сделать, - убедить операционную систему не скрывать записи на диск агрессивно, так как вам действительно все равно, когда/если они попадают на диск.

В Linux вы можете управлять этим с помощью подсистемы виртуальной памяти dirty_*, например dirty_writeback_centisecs.

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

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

В более новых ядрах вы можете убедиться, что vm.zone_reclaim_mode установлено на ноль, так как это может вызвать серьезные проблемы с производительностью в системах NUMA (большинство систем в наши дни) из-за взаимодействия с тем, как PostgreSQL управляет shared_buffers.

Настройка запросов и рабочей нагрузки

Это вещи, для которых требуются изменения кода; они могут вас не устраивать. Некоторые из них могут быть применены.

Если вы не планируете работу над большими транзакциями, запустите. Многие небольшие транзакции стоят дорого, поэтому вы должны периодически делиться материалами, когда это возможно и практично. Если вы используете async commit, это менее важно, но все же рекомендуется.

По возможности используйте временные таблицы. Они не генерируют WAL-трафик, поэтому они намного быстрее для вставок и обновлений. Иногда стоит засыпать кучу данных в временную таблицу, манипулируя ею, но вам нужно, а затем INSERT INTO ... SELECT ... скопировать ее в финальную таблицу. Обратите внимание, что временные таблицы относятся к сеансу; если ваш сеанс заканчивается или вы теряете соединение, тогда временная таблица исчезает, и никакое другое соединение не может видеть содержимое таблицы (ов) временной сессии сеанса.

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

В общем случае не DELETE FROM blah;. Вместо этого используйте TRUNCATE TABLE blah;; это намного быстрее, когда вы сбрасываете все строки в таблице. Усекайте многие таблицы одним вызовом TRUNCATE, если сможете. Там оговорка, если вы делаете много TRUNCATES маленьких таблиц снова и снова, хотя; см. Скорость усечения Postgresql

Если у вас нет индексов для внешних ключей, DELETE с участием первичных ключей, на которые ссылаются эти внешние ключи, будет ужасно медленным. Не забудьте создать такие индексы, если вы когда-либо ожидали DELETE из ссылочной таблицы (таблиц). Индексы не требуются для TRUNCATE.

Не создавайте индексы, которые вам не нужны. Каждый индекс имеет стоимость обслуживания. Попытайтесь использовать минимальный набор индексов и позволить сканирование растровых индексов сочетать их, а не поддерживать слишком много огромных, дорогостоящих многоколоночных индексов. Если требуются индексы, сначала попробуйте заполнить таблицу, а затем создайте индексы в конце.

Оборудование

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

Если у вас недостаточно ОЗУ, тем быстрее вы сможете получить лучшее хранилище. Даже дешевый SSD делает огромную разницу в ржавчине. Не доверяйте дешевым SSD для производства, хотя они часто не являются аварийными и могут съесть ваши данные.

Обучение

Книга Грега Смита, Высокая производительность PostgreSQL 9.0 остается актуальной, несмотря на несколько более старую версию. Это должно быть полезной ссылкой.

Присоединитесь к списку рассылки PostgreSQL и следуйте за ним.

Чтение:

Ответ 2

Используйте разный макет диска:

  • другой диск для $PGDATA
  • другой диск для $PGDATA/pg_xlog
  • другой диск для временных файлов (для каждой базы данных $PGDATA/base//pgsql_tmp) (см. примечание о work_mem)

Настройки postgresql.conf:

  • shared_memory: 30% доступной оперативной памяти, но не более 6 - 8 ГБ. Кажется, лучше иметь меньше разделяемой памяти (2 ГБ - 4 ГБ) для интенсивных рабочих нагрузок.
  • work_mem: в основном для выбранных запросов с сортировками/агрегациями. Это для каждого параметра соединения, и запрос может распределять это значение несколько раз. Если данные не подходят, то используется диск (pgsql_tmp). Проверьте "объяснить анализ", чтобы узнать, сколько памяти вам нужно.
  • fsync и synchronous_commit: значения по умолчанию безопасны, но если вы можете переносить потерянные данные, тогда вы можете отключить их
  • random_page_cost: если у вас есть SSD или быстрый RAID-массив, вы можете снизить его до 2.0 (RAID) или даже ниже (1.1) для SSD
  • checkpoint_segments: вы можете пойти выше 32 или 64 и изменить checkpoint_completion_target на 0.9. Более низкое значение позволяет быстрее после аварийного восстановления