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

203

Я переключаюсь на PostgreSQL из SQLite для типичного приложения Rails.

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

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

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

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

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

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

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

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

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

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

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

Некоторые цифры для ~ 700 тестов.

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

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

Дмитрий Нагирняк
источник
2
Я действительно сомневаюсь, что вы сделаете так быстро, как SQLite. SQLite с одним пользователем работает безумно быстро. Дизайн SQLite очень быстрый, с низким количеством пользователей и плохо масштабируется; Дизайн Pg хорошо масштабируется, но не так быстр для простой работы с одним пользователем.
Крейг Рингер
1
Я понимаю это, но есть особый случай, когда я надеюсь оптимизировать PG для (тестовых прогонов), чтобы он был настолько быстрым, насколько это возможно. Я не против, чтобы там было немного медленнее, но 2.2x слишком медленный. Видишь, о чем я?
Дмитрий Нагирняк
+1 Я был бы очень заинтересован в обновлениях подхода к RAM-диску, если у вас есть какие-либо результаты по этому поводу.
tscho
@tscho Я обязательно опубликую это здесь. Но нужно некоторое время, так как я работаю над другими вещами и «исследую» вещи PG в «фоне».
Дмитрий Нагирняк
является вставив в данной вашу проблему или запрос ? Это не ясно из вашего вопроса.
a_horse_with_no_name

Ответы:

281

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

Этикет

Вы НЕ положить табличного на Ramdisk или другой недлительного хранения .

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

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

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

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

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

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

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

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

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

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

Если вы используете только пару соединений, которые выполняют большую работу, увеличьте их, work_memчтобы дать им больше оперативной памяти для игр для сортировки и т. Д. Помните, что слишком высокое значение work_memпараметра может вызвать проблемы нехватки памяти, потому что это не для каждого соединения, поэтому один запрос может иметь много вложенных сортировок. Вам действительно нужно увеличивать, только 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.

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

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

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

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

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

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

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

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

аппаратные средства

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

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

Обучение

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

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

Чтение:

Крейг Рингер
источник
10
Я также могу порекомендовать PostgreSQL 9.0 High Performance от @GregSmith, это действительно отличное чтение. Книга охватывает все аспекты настройки производительности, от разметки диска до настройки запросов, и дает вам очень хорошее понимание внутренних возможностей PG.
tscho
10
Я не выпустил обновление для книги для PostgreSQL 9.1, единственной версии с момента ее публикации, потому что в 9.1 не было достаточно изменений, связанных с производительностью, чтобы это оправдать.
Грег Смит
3
Отличная рецензия. Как небольшое обновление, «вам может потребоваться увеличить максимальный лимит разделяемой памяти в ОС, если вы увеличите shared_buffers», больше не верно (для большинства пользователей) в PostgreSQL 9.3: postgresql.org/docs/9.3/static/release-9- 3.html # AEN114343
Гуннлаугур
1
@brauliobo Мои тесты часто делают много tx при высоких TPS ... потому что я пытаюсь смоделировать производство, в том числе с высокой нагрузкой параллелизма. Если вы имеете в виду «линейное тестирование с одним соединением», то я бы с вами согласился.
Крейг Рингер
1
stackoverflow.com/questions/11419536/… DELETE может быть быстрее, чем TRUNCATE для таблиц с несколькими строками, что, вероятно, имеет место в тестах.
Джонатан Кросмер
9

Используйте другую структуру диска:

  • другой диск для $ 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. Более низкое значение обеспечивает более быстрое восстановление после сбоя
МЫС
источник
4
Обратите внимание, что если вы уже работаете с fsync=off, размещение pg_xlog на отдельном диске больше не улучшится.
интегрирования
Значение 1,1 для твердотельного накопителя кажется очень безоговорочным. Я признаю, что это то, что некоторые специалисты слепо рекомендовали. Даже твердотельные накопители значительно быстрее при последовательном чтении, чем при случайном чтении.
Acumenus
@ABB Да, но у вас также есть эффекты кэширования буфера ОС на работе. В любом случае, все эти параметры немного волнуют ...
Крейг Рингер