Оптимизация производительности
На производительность запросов влияет множество факторов. Часть из них может контролироваться пользователем или администратором, на другие наибольшее влияние оказывает базовая архитектуры системы. В этой статье представлены несколько рекомендаций по настройке производительности PostgreSQL.
Оптимизация потребления ресурсов
В этом разделе содержатся общие рекомендации по значениям конфигурационных параметров, которые можно использовать в качестве отправной точки. Оптимальные значения параметров зависят от нагрузки конкретного кластера и используемого оборудования. Обратите внимание, что существуют конфигураторы с открытым исходным кодом, которые рассчитывают значения основных настроек PostgreSQL на основе указанной конфигурации оборудования. Некоторые из них доступны онлайн.
Настройки памяти
В таблице ниже приведены базовые рекомендации по значениям настроек памяти в зависимости от размера памяти сервера.
Название параметра | Описание | Рекомендуемое значение |
---|---|---|
effective_cache_size |
Определяет представление планировщика об эффективном размере дискового кeша, доступном для одного запроса. Это значение учитывается при оценке стоимости использования индекса. Более высокое значение увеличивает вероятность использования сканирования индекса, более низкое значение повышает вероятность применения последовательного сканирования. При настройке этого параметра следует учитывать как разделяемые буферы PostgreSQL (shared buffers), так и часть дискового кеша ядра, которая будет использоваться для файлов данных PostgreSQL, хотя некоторые данные могут существовать и там, и там. Также необходимо учитывать ожидаемое количество одновременных запросов к разным таблицам, поскольку им придется делить доступное пространство. Этот параметр не влияет на размер общей памяти, выделяемой PostgreSQL, и не резервирует дисковый кеш ядра. Он используется только в целях оценки. Система также не предполагает, что данные остаются в дисковом кеше между запросами. Если значение |
2/3 RAM |
shared_buffers |
Устанавливает объем памяти, который сервер базы данных использует для буферов в разделяемой памяти. Если у вас есть выделенный сервер базы данных с 1 ГБ или более оперативной памяти, разумное начальное значение для |
RAM/4 |
temp_buffers |
Устанавливает максимальный объем памяти, используемый для временных буферов в каждой сессии. Эти существующие только в пределах сессии буферы используются для доступа к временным таблицам. Если значение параметра указано без единиц измерения, оно считается заданным в блоках, размер которых равен |
256 МБ |
work_mem |
Устанавливает базовый максимальный объем памяти, который будет использоваться операцией запроса (например, сортировкой или хеш-таблицей) перед записью во временные файлы на диске. Обратите внимание, что для сложного запроса несколько операций сортировки или хеширования могут выполняться параллельно. Каждой операции будет разрешено использовать столько памяти, сколько указано в этом значении, прежде чем начнется запись во временные файлы. Несколько запущенных сессий также могут выполнять такие операции одновременно. Следовательно, общий объем используемой памяти может во много раз превышать значение |
RAM/32 |
maintenance_work_mem |
Указывает максимальный объем памяти, который будет использоваться операциями обслуживания базы данных, такими как Обратите внимание, что при запуске автовакуума эта память может быть выделена до autovacuum_max_workers раз, поэтому будьте осторожны и не устанавливайте слишком высокое значение. Может быть полезно использовать конфигурационный параметр autovacuum_work_mem для управления автовакуумом |
RAM/16 |
Все описанные параметры, кроме autovacuum_work_mem
и temp_buffers
, можно установить в разделе ADPG configurations дерева Configuration на странице Clusters → Кластер ADPG → Services → ADPG → Primary configuration в пользовательском интерфейсе ADCM.
После изменения описанных настроек выполните действие Reconfigure & Restart сервиса ADPG, чтобы применить изменения.
Настройки, связанные с операциями ввода-вывода
В таблице ниже перечислены параметры, связанные с операциями ввода-вывода, изменение значений которых может значительно влиять на производительность.
Название параметра | Описание |
---|---|
fsync |
Если этот параметр включен, сервер PostgreSQL пытается убедиться, что обновления физически записываются на диск, выполняя системные вызовы Примеры, когда отключение Во многих ситуациях отключение Параметр |
synchronous_commit |
Определяет, после завершения какого уровня обработки WAL сервер базы данных вернет клиенту сообщение об успехе. См. synchronous_commit. Установка для этого параметра значения Поведение каждой транзакции определяется значением, действующим в момент её фиксирования. Таким образом, есть возможность фиксировать некоторые транзакции синхронно, а другие — асинхронно. Например, чтобы зафиксировать одну транзакцию из нескольких команд асинхронно, когда по умолчанию выбрано другое значение, выполните в этой транзакции |
checkpoint_completion_target |
Указывает целевое время завершения контрольной точки как долю общего времени между контрольными точками. Значение по умолчанию — |
effective_io_concurrency |
Устанавливает количество дисковых операций ввода-вывода, которые могут выполняться одновременно. Увеличение этого значения увеличит количество операций ввода-вывода, которые сессия PostgreSQL пытается инициировать параллельно. Допустимый диапазон — от Для магнитных дисков хорошей отправной точкой для этого параметра является количество отдельных дисков, составляющих массив RAID 0 или RAID 1, в котором размещена базы данных. Для RAID 5 следует исключить диск четности. Если база данных часто перегружена несколькими запросами, выполняемыми в одновременных сессиях, меньших значений может быть достаточно, чтобы дисковый массив был занят. Значение, превышающее необходимое для занятости дисков, приведет только к дополнительной нагрузке на процессор. SSD-накопители часто могут обрабатывать множество одновременных запросов, поэтому оптимальное значение может исчисляться сотнями. Это значение можно переопределить для таблиц в определенном табличном пространстве, задав одноименный параметр табличного пространства (см. ALTER TABLESPACE ) |
random_page_cost |
Устанавливает приблизительную стоимость чтения одной страницы с диска, извлекаемой непоследовательно, для планировщика. Значение по умолчанию — Уменьшение Произвольный доступ к механическому дисковому хранилищу обычно обходится намного дороже последовательного доступа, более чем в четыре раза. Однако используется более низкое значение по умолчанию ( Если вы считаете, что доля операций, выполняемых из кеша, равная 90 %, является неправильным предположением для вашей рабочей нагрузки, вы можете увеличить Это значение можно переопределить для таблиц и индексов в определенном табличном пространстве, задав одноименный параметр табличного пространства (см. ALTER TABLESPACE) |
Мониторинг загрузки диска
В ADPG/PostgreSQL для каждой таблицы создается первичный дисковый heap-файл, в котором хранится большая часть данных. Если в таблице есть столбцы с потенциально большими значениями, с ней также может быть связан TOAST-файл, который используется для хранения этих больших значений. Для каждой TOAST-таблицы на диске будет храниться один валидный индекс. Также могут быть индексы, связанные с базовой таблицей. PostgreSQL хранит каждую таблицу и индекс в отдельном дисковом файле. Если размер файла превышает 1 ГБ, будут созданы дополнительные файлы. Соглашения об именах для этих файлов описаны в статье Database file layout.
Вы можете осуществлять мониторинг дискового пространства тремя способами:
Использование SQL-функции для определения размеров объектов базы данных
Функции SQL наиболее просты в использовании и обычно рекомендуется применять их. Они перечислены в таблице Database object size functions.
Например, функция pg_relation_size()
возвращает указанный размер таблицы (в данном примере — pgbench_accounts
) в байтах. Вы можете использовать psql для выполнения следующего запроса:
SELECT pg_relation_size('pgbench_accounts');
Результат:
pg_relation_size ------------------ 671481856
Функция pg_size_pretty()
преобразует размер в байтах в более удобный для чтения формат с единицами измерения: байты, КБ, МБ, ГБ или ТБ:
SELECT pg_size_pretty(pg_relation_size('pgbench_accounts'));
Результат:
pg_size_pretty ---------------- 640 MB
Можно использовать функцию pg_database_size()
для вычисления общего дискового пространства, занимаемого указанной базой данных (в данном примере example
):
SELECT pg_size_pretty (pg_database_size('example'));
Результат:
pg_size_pretty ---------------- 756 MB
Просмотр системных каталогов
Можно выполнить запросы в psql
, чтобы увидеть использование диска таблицей. Для достоверности результатов над таблицей предварительно должна быть выполнена операция VACUUM или ANALYZE. Следующий запрос определяет количество страниц (столбец relpages
), принадлежащих таблице pgbench_accounts
:
SELECT pg_relation_filepath(oid), relpages FROM pg_class WHERE relname = 'pgbench_accounts';
Результат:
pg_relation_filepath | relpages ----------------------+---------- base/19191/19244 | 81968
Каждая страница обычно имеет размер 8 КБ. Запрос вернул тот же результат, который возвращает функция pg_relation_size()
: КБ. Обратите внимание, что relpages
обновляется только с помощью VACUUM
, ANALYZE
и нескольких команд DDL, таких как CREATE INDEX
. Путь к файлу (столбец pg_relation_filepath
) представляет интерес, если вы хотите напрямую просмотреть файл таблицы на диске.
Чтобы определить пространство, занимаемое таблицами TOAST, связанными с таблицей my_table
, используйте следующий запрос:
SELECT relname, relpages
FROM pg_class,
(SELECT reltoastrelid
FROM pg_class
WHERE relname = 'my_table') AS ss
WHERE oid = ss.reltoastrelid OR
oid = (SELECT indexrelid
FROM pg_index
WHERE indrelid = ss.reltoastrelid)
ORDER BY relname;
Результат:
relname | relpages -----------------------+---------- pg_toast_295925 | 0 pg_toast_295925_index | 1
Запрос ниже отображает размер индекса для таблицы pgbench_branches
:
SELECT c2.relname, c2.relpages
FROM pg_class c, pg_class c2, pg_index i
WHERE c.relname = 'pgbench_branches' AND
c.oid = i.indrelid AND
c2.oid = i.indexrelid
ORDER BY c2.relname;
Результат:
relname | relpages -----------------------+---------- ind_bbalance | 2 pgbench_branches_pkey | 2
Чтобы найти самые большие таблицы и индексы, используйте следующий запрос:
SELECT relname, relpages
FROM pg_class
ORDER BY relpages DESC LIMIT 5;
Результат:
relname | relpages -----------------------+---------- pgbench_accounts | 81968 pgbench_accounts_pkey | 13713 pg_proc | 94 pg_depend | 65 pg_toast_2618 | 63
Использование модуля oid2name
Утилита oid2name помогает администраторам проверять файловую структуру, используемую ADPG/PostgreSQL.
oid2name
подключается к целевой базе данных и извлекает OID, файловый узел (filenode — уникальный числовой идентификатор, используемый для именования файлов на диске, принадлежащих отношению) и/или информацию об имени таблицы:
$ oid2name
Результат:
All databases: Oid Database Name Tablespace ----------------------------------- 19191 example pg_default 14486 postgres pg_default 14485 template0 pg_default 1 template1 pg_default
Например, можно рассмотреть базу данных example
из списка, приведенного выше. Для этого измените текущий каталог на каталог базы данных:
$ cd /pg_data1/adpg16/base/19191
где 19191
— Oid базы данных example
из вывода команды, приведенного выше.
Отобразите первые 5 объектов базы данных в табличном пространстве по умолчанию, отсортированные по размеру (самые большие):
$ ls -lS * | head -5
Результат:
-rw------- 1 postgres postgres 671481856 Jul 31 10:54 19244 -rw------- 1 postgres postgres 112336896 Jul 31 11:03 19261 -rw------- 1 postgres postgres 770048 Jul 31 10:43 1255 -rw------- 1 postgres postgres 532480 Aug 1 08:11 2608 -rw------- 1 postgres postgres 516096 Jul 31 10:43 2838
Определите, что за файл 19244
:
$ oid2name -d example -f 19244
Результат:
Filenode Table Name ---------------------------- 19244 pgbench_accounts
Для утилиты oid2name
требуется работающий сервер базы данных с неповрежденными системными каталогами. В ситуациях со значительными повреждением базы данных её использование ограничено.
Наполнение базы данных
Этот раздел содержит рекомендации о том, как эффективно добавлять большие объемы данных при первом заполнении базы или в процессе её использования.
Отключение автофиксации транзакций
При использовании нескольких операторов INSERT
отключите автофиксацию и выполните одну фиксацию в конце транзакции. В обычном SQL это означает выполнение BEGIN в начале и COMMIT в конце. Некоторые клиентские библиотеки могут делать это автоматически, в этом случае нужно проверить, что это действительно так. Если вы разрешите фиксацию каждого оператора INSERT
отдельно, PostgreSQL проделает большую работу для каждой добавленной строки. Дополнительным преимуществом выполнения всех вставок за одну транзакцию является то, что в случае сбоя добавления одной строки, вставка всех строк будет отменена. Таким образом, вы не получите базу с частично загруженными данными.
Использование COPY
Используйте COPY, чтобы загрузить все строки одной командой вместо выполнения серии команд INSERT
. Команда COPY
оптимизирована для загрузки большого количества строк. Она менее гибкая, чем INSERT
, но имеет значительно меньшие издержки при больших загрузках данных. Поскольку COPY
— это одна команда, нет необходимости отключать автофиксацию, если используется этот метод для заполнения таблицы.
Если невозможно использовать COPY
, будет полезно применить PREPARE для создания подготовленного оператора INSERT
, а затем использовать EXECUTE столько раз, сколько необходимо. Это позволит избежать накладных расходов на повторный анализ и планирование INSERT
.
Обратите внимание, что загрузка большого количества строк с помощью COPY
почти всегда происходит быстрее, чем с помощью INSERT
, даже если используется PREPARE
и несколько вставок объединяются в одну транзакцию.
Если параметр wal_level
имеет значение minimal
, команда COPY
работает быстрее всего, когда выполняется в той же транзакции, что и команды CREATE TABLE
или TRUNCATE
. В таких случаях писать WAL не нужно, поскольку в случае ошибки файлы, содержащие вновь загруженные данные, будут удалены.
Удаление индексов
Если вы загружаете данные в только что созданную таблицу, самый быстрый способ — добавить данные с помощью COPY
, а затем создать индексы. Создание индекса для существующих данных занимает меньше времени, чем его последовательное обновление при добавлении каждой строки.
Если вам нужно добавить большие объемы данных в существующую таблицу, возможно, имеет смысл удалить индексы, загрузить таблицу, а затем воссоздать индексы. Обратите внимание, что производительность базы данных для других пользователей может снизиться, пока индексы отсутствуют. Кроме того, следует дважды подумать, прежде чем удалять уникальные индексы, так как без них не будут выполняться соответствующие проверки ключей.
Удаление ограничений внешних ключей
Как и в случае с индексами, ограничение внешнего ключа можно более эффективно проверять массово, чем построчно. Может быть полезно удалить ограничения внешнего ключа, загрузить данные и заново создать ограничения. В этом случае приходится выбирать между скоростью загрузки данных и потерей проверки ошибок при отсутствии ограничения.
Более того, когда вы загружаете данные в таблицу с существующими ограничениями внешнего ключа, каждая новая строка требует записи в списке ожидающих событий триггера сервера, поскольку именно срабатывающий триггер проверяет ограничение внешнего ключа строки. Загрузка многих миллионов строк может привести к тому, что очередь событий триггера переполнит доступную память, что приведет к недопустимой нагрузке на файл подкачки или даже сбою команды. Поэтому может быть необходимо, а не просто желательно, удалять и восстанавливать внешние ключи при загрузке больших объемов данных. Если временное удаление ограничения неприемлемо, единственным возможным решением может быть разделение операции загрузки на более мелкие транзакции.
Увеличение maintenance_work_mem
Временное увеличение параметра конфигурации maintenance_work_mem при загрузке больших объемов данных может улучшить ситуацию с производительностью. Это помогает ускорить выполнение команд CREATE INDEX
и ALTER TABLE ADD FOREIGN KEY
, но не влияет на скорость выполнения команды COPY
, поэтому данный совет полезен только в том случае, если вы используете один или оба описанных выше метода. maintenance_work_mem
находится в разделе ADPG configurations дерева Configuration на странице Clusters → Кластер ADPG → Services → ADPG → Primary configuration в пользовательском интерфейсе ADCM. См. Конфигурационные параметры.
Увеличение max_wal_size
Временное увеличение параметра конфигурации max_wal_size также может ускорить загрузку больших данных. Загрузка большого объема данных приводит к тому, что контрольные точки возникают чаще, чем обычно (задается параметром конфигурации checkpoint_timeout
). При возникновении контрольной точки все "грязные" страницы должны быть сброшены на диск. Количество необходимых контрольных точек можно уменьшить, увеличив max_wal_size
во время массовой загрузки данных. max_wal_size
также находится в разделе ADPG configurations дерева Configuration на странице Clusters → Кластер ADPG → Services → ADPG → Primary configuration в пользовательском интерфейсе ADCM.
Отключение архивации WAL и создания бэкапов
При загрузке больших объемов данных в кластер, использующий архивацию WAL и потоковую репликацию, может быть быстрее создать новую базовую резервную копию после завершения загрузки, чем обрабатывать большой объем инкрементных данных WAL.
Чтобы отключить архивирование WAL, установите следующие параметры конфигурации:
-
wal_level —
minimal
; -
archive_mode —
off
; -
max_wal_senders —
0
.
Чтобы задать эти параметры, используйте раздел ADPG configurations на вкладке Clusters → Кластер ADPG → Services → ADPG → Primary configuration в пользовательском интерфейсе ADCM. См. Конфигурационные параметры.
Чтобы отключить создание бэкапов, выключите переключатель Enable backups, отображаемый на вкладке Primary Configuration сервиса ADPG (Clusters → Кластер ADPG → Services → ADPG → Primary configuration).
Для применения изменений этих параметров, выполните действие Reconfigure & Restart.
ВАЖНО
Отключение архивирования WAL делает резервные копии, сделанные ранее, непригодными для восстановления из архива и использования резервным сервером, и может привести к потере данных.
|
Эти настройки также ускоряют выполнение некоторых команд, поскольку команды не записывают WAL, если для параметра wal_level
установлено значение minimal
.
Выполнение ANALYZE по завершении
Если вы существенно изменили распределение данных в таблице, настоятельно рекомендуется запустить команду ANALYZE. Выполнение ANALYZE
(или VACUUM ANALYZE
) гарантирует, что у планировщика будет актуальная статистика о таблице. При отсутствии статистики или устаревшей статистике планировщик может принять неправильные решения во время планирования запроса, что приведет к снижению производительности. Обратите внимание, что если autovacuum включен, он может автоматически запустить ANALYZE
.
Улучшение производительности pg_dump
Скрипты дамп-файлов, созданные с помощью pg_dump, автоматически применяют некоторые, но не все, из приведенных выше рекомендаций. Чтобы восстановить дамп как можно быстрее, нужно сделать несколько дополнительных действий вручную. Обратите внимание, что эти рекомендации следует применять при восстановлении дампа, а не при его создании.
По умолчанию pg_dump
использует COPY
. Кроме того, когда генерируется полный дамп схемы и данных, данные загружаются перед созданием индексов и внешних ключей. Таким образом, некоторые рекомендации применяются автоматически. Все, что вам нужно учитывать, это следующее:
-
Установите соответствующие (большие, чем обычно) значения для
maintenance_work_mem
иmax_wal_size
. -
Если вы используете архивацию или потоковую репликацию WAL, отключите их во время восстановления, как описано в разделе Отключение архивации WAL и создания бэкапов.
-
Поэкспериментируйте с режимами параллельного создания дампа и восстановления утилит
pg_dump
иpg_restore
и найдите оптимальное количество одновременных процессов. Параллельное копирование и восстановление данных, управляемое опцией-j
, должно дать значительно более высокую производительность по сравнению с последовательным режимом. -
В некоторых случаях может быть предпочтительно восстановить дамп за одну транзакцию. Для этого передайте параметр командной строки
-1
или--single-transaction
вpsql
илиpg_restore
. КомандыCOPY
также будут выполняться быстрее, если вы ограничитесь одной транзакцией и отключите архивирование WAL. Обратите внимание, что при использовании этого режима даже малейшие ошибки откатят процесс восстановления полностью, что может привести к потере многих часов обработки. -
Если на сервере базы данных доступно несколько процессоров (CPU), рассмотрите возможность использования опции
--jobs
утилитыpg_restore
. Это позволяет одновременно загружать данные и создавать индексы. -
Запустите
ANALYZE
после восстановления.
Дамп данных (data-only dump) также использует COPY
, но он не удаляет и не воссоздает индексы и по умолчанию не работает с внешними ключами. Таким образом, при загрузке дампа, содержащего только данные, вы несете ответственность за удаление и воссоздание индексов и внешних ключей. По-прежнему полезно увеличивать max_wal_size
при загрузке данных, но не maintenance_work_mem
. maintenance_work_mem
стоит менять только в том случае, если вы вручную воссоздаете индексы и внешние ключи. Также рекомендуется запустить ANALYZE
в конце восстановления.