Регулярные задачи обслуживания базы данных

QHB, как и любое программное обеспечение для баз данных, для достижения оптимальной производительности требует, чтобы определенные задачи выполнялись регулярно . Обсуждаемые здесь задачи являются обязательными, но они повторяемые и могут быть легко автоматизированы с помощью стандартных инструментов, таких как сценарии cron. Администратор базы данных отвечает за установку соответствующих сценариев и проверку их успешного выполнения.

Одной из очевидных задач обслуживания является создание резервных копий данных на регулярной основе. Без последней резервной копии у вас нет шансов на восстановление после катастрофы (сбой диска, пожар, ошибочное удаление критической таблицы и т. д.). Механизмы резервного копирования и восстановления, доступные в QHB, подробно обсуждаются в главе Резервное копирование и восстановление.

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

Другая задача, которая может потребовать периодического внимания, — это управление файлами журналов. Она обсуждается в разделе Обслуживание файла журнала.

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

Регулярная очистка

Базы данных QHB требуют периодического обслуживания, известного как очистка («vacuum»). Для многих установок достаточно, чтобы процесс vacuum выполнял только автоматическую очистку, как описано в разделе Процесс «Автовакуум». Возможно, вам придется настроить параметры autovacuum, описанные там, чтобы получить наилучшие результаты для вашей установки. Некоторые администраторы баз данных захотят дополнить или заменить действия автоочистки командами VACUUM с ручным управлением, которые обычно выполняются в соответствии с расписанием с помощью сценариев cron. Чтобы правильно настроить процесс vacuum с ручным управлением, важно понимать вопросы, обсуждаемые в следующих нескольких подразделах. Администраторы, которые полагаются на автоочистку, могут ознакомится с этим материалом, чтобы лучше понять как настроить autovacuum.

Основы vacuum

Команда QHB VACUUM должна обрабатывать каждую таблицу на регулярной основе по нескольким причинам:

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

  2. для обновления статистики данных используемых планировщиком запросов QHB;

  3. для обновления карты видимости, которая ускоряет Сканирование только по индексу и покрывающие индексы;

  4. для защиты от потери очень старых данных из-за "закольцовывания" идентификатора транзакции или мультранзакционного идентификатора.

Каждая из этих причин требует выполнение операций VACUUM различной частоты и объема, что будет объяснено в следующих подразделах.

Существует два варианта VACUUM: стандартный VACUUM и VACUUM FULL. VACUUM FULL может освободить больше места на диске, но работает намного медленнее. Кроме того, стандартная форма VACUUM может работать параллельно с другими операциями базы данных. (Такие команды, как SELECT, INSERT, UPDATE и DELETE, продолжат нормально функционировать, хотя вы не сможете изменять определение таблицы с помощью команд, таких как ALTER TABLE во время очистки). VACUUM FULL требует эксклюзивной блокировки на таблицы, с которыми он работает, и, следовательно, не может быть выполнен параллельно с другим использованием таблицы. Поэтому, как правило, администраторы должны стремиться использовать стандартный VACUUM и избегать VACUUM FULL.

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

Восстановление дискового пространства

В QHB UPDATE или DELETE строки не сразу удаляют старую версию строки. Этот подход необходим для получения преимуществ многоверсионного управления параллелизмом: нельзя удалять версию строки, пока она потенциально может быть видна другим транзакциям. Но в конце концов устаревшая или удаленная версия строки больше не представляет интереса для какой-либо транзакции. Затем занимаемое им пространство должно стать доступно для повторного использования новыми строками, чтобы избежать неограниченного роста требований к дисковому пространству. Это достигается с помощью процесса VACUUM.

Стандартная форма VACUUM удаляет версии "мертвых" строк в таблицах и индексах и отмечает пространство, доступное для повторного использования в будущем. Однако он не вернет пространство операционной системе, за исключением особого случая, когда одна или несколько страниц в конце таблицы становятся полностью свободными, и можно легко получить эксклюзивную блокировку таблицы. Напротив, VACUUM FULL активно уплотняет таблицы, записывая полную новую версию файла таблицы без пустого пространства. Это минимизирует размер таблицы, но может занять очень много времени. Также требуется дополнительное дисковое пространство для новой копии таблицы, пока операция не завершится.

Обычно, цель очистки состоит в том, чтобы выполняьб стандартный VACUUM достаточно часто, чтобы избежать необходимости запуска VACUUM FULL. Фоновый процесс autovacuum пытается работать таким образом, и фактически никогда не применяет VACUUM FULL. Идея такого подхода состоит не в том, чтобы поддерживать минимальный размер таблиц, а в том, чтобы поддерживать устойчивое равномерное использование дискового пространства: каждая таблица занимает пространство, эквивалентное ее минимальному размеру, тем не менее, много места может использоваться между очистками. Хотя VACUUM FULL можно использовать для сокращения таблицы до минимального размера и возврата дискового пространства в операционную систему, в этом нет особого смысла, если таблица в будущем снова будет расти. Таким образом, стандартные прогоны VACUUM с умеренной частотой являются лучше, чем редкие прогоны VACUUM FULL, для обрабоки значительно обновленных таблиц.

Некоторые администраторы предпочитают планировать VACUUM самостоятельно, например, выполняя всю работу ночью при низкой нагрузке. Сложность выполнения очистки по фиксированному расписанию состоит в том, что если в таблице неожиданно наблюдается всплеск активности обновления, она может раздуться до такой степени, что VACUUM FULL станет действительно необходим для освобождения места. Использование фонового процесса autovacuum облегчает эту задачу, поскольку фоновый процесс планирует динамическое удаление "мёртвых" строк в ответ на действия по обновлению. Неразумно полностью отключать фоновый процесс, если у вас нет стопроцентно предсказуемой рабочей нагрузки. Одним из возможных компромиссов является установка параметров фонового процесса так, чтобы он реагировал только на необычайно интенсивную деятельность по обновлению, таким образом не давая системе выйти из-под контроля, в то время как запланированные процессы VACUUM должны выполнять основную часть работы, когда нагрузка является типичной.

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

Заметка
Результаты простого VACUUM могут быть неудовлетворительными, если в таблице содержится большое количество версий "мертвых" строк в результате массового обновления или удаления. Если у вас есть такая таблица и вам нужно освободить занимаемое ею избыточное дисковое пространство, вам нужно будет использовать VACUUM FULL или, альтернативно, CLUSTER или один из вариантов перезаписи таблицы ALTER TABLE. Эти команды переписывают новую копию таблицы и строят для нее новые индексы. Все эти опции требуют эксклюзивной блокировки. Обратите внимание, что они также временно используют дополнительное дисковое пространство, приблизительно равное размеру таблицы, поскольку старые копии таблицы и индексов не могут быть освобождены, пока не будут созданы новые.

Заметка
Если у вас есть таблица, все содержимое которой периодически удаляется, попробуйте сделать это с помощью TRUNCATE, а не с помощью DELETE а затем выполните VACUUM. TRUNCATE немедленно удаляет все содержимое таблицы, не требуя последующего VACUUM или VACUUM FULL для восстановления неиспользуемого дискового пространства. Недостатком является то, что строгая семантика MVCC нарушается.

Обновление статистики планировщика

Планировщик запросов QHB полагается на статистическую информацию о содержимом таблиц для создания хороших планов для запросов. Эти статистические данные собираются с помощью команды ANALYZE, которую можно вызвать отдельно или в качестве необязательного шага в VACUUM. Важно иметь достаточно точную статистику, иначе неверный выбор планов выполнения может значительно снизить производительность базы данных.

Фоновый процесс autovacuum, если он включен, будет автоматически запускать команды ANALYZE всякий раз, когда содержимое таблицы в достаточной степени изменяется . Однако администраторы могут предпочесть полагаться на запланированные вручную операции ANALYZE, особенно если известно, что активность обновления таблицы не повлияет на статистику «интересующих» планировщик столбцов (которые интенсивно используются в WHERE). Фоновый процесс autovacuum планирует ANALYZE строго в зависимости от количества вставленных или обновленных строк - он не знает, приведет ли это к значимым статистическим изменениям.

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

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

Заметка
Хотя подстройка частоты ANALYZE каждого столбца может быть и не очень продуктивной, может оказаться целесообразным выполнить для каждого столбца настройку уровня детализации статистики, собираемой ANALYZE. Столбцы, которые интенсивно используются в WHERE и имеют очень нерегулярное распределение данных, могут потребовать более детальной гистограммы данных, чем другие столбцы. См. ALTER TABLE SET STATISTICS или можно изменить значение по умолчанию для всей базы данных, используя параметр конфигурации default_statistics_target.

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

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

Обновление карты видимости

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

  • Во-первых, сам VACUUM может пропустить такие страницы при следующем запуске, так как нечего убирать.

  • Во-вторых, страницы видимости позволяют QHB отвечать на некоторые запросы, используя только индекс, без ссылки на базовую таблицу. Поскольку индексы QHB не содержат информации о видимости строки, при обычном сканировании индекса строка выбирается для каждой соответствующей записи индекса, чтобы проверить, должна ли она быть видимой текущей транзакцией. С другой стороны, сканирование только по индексу сначала проверяет карту видимости. Если известно, что все кортежи на странице видны, выборка может быть пропущена. Это наиболее полезно для больших наборов данных, где карта видимости может предотвратить лишний доступ к диску. Карта видимости значительно меньше списка всех блоков, поэтому ее можно легко кэшировать, даже если блоков очень много.

Предотвращение ошибок зацикливания идентификатора транзакции

Семантика транзакции MVCC в QHB зависит от возможности сравнения номеров идентификаторов транзакций (XID): версия строки с XID вставки, превышающим XID текущей транзакции, находится «в будущем» и не должна быть видимой для текущей транзакции. Но поскольку идентификаторы транзакций имеют ограниченный размер 32 бита, кластер, работающий в течение длительного времени (более 4 миллиардов транзакций), будет подвергаться циклическому изменению идентификатора транзакции (закольцовывание, wraparound): счетчик XID обнуляется, и все транзакции, которые были в прошлом внезапно окажутся в будущем - что означает, что их значения становится невидимы. В итоге произойдёт катастрофическая потеря данных. (На самом деле данные все еще там, но это не поможет, если нет возможности их получить). Чтобы избежать этого, необходимо запустить VACUUM для каждой таблицы в каждой базе данных как минимум один раз каждые два миллиарда транзакций.

Причина, по которой периодический запуск VACUUM решает проблему, состоит в том, что VACUUM помечает строки как "замороженные" (freeze), указывая на то, что они были установлены транзакцией, зафиксированной достаточно давно, и что изменения этой транзакции будут видны для всех текущих и будущих транзакций., Нормальные XID сравниваются с использованием арифметики по модулю 2 **32 **. Это означает, что для каждого нормального XID существует два миллиарда «более старых» и два миллиарда «более новых» значений. После создания версии строки с определенным нормальным XID версия строки будет «в прошлом» для следующих двух миллиардов транзакций, независимо от того, о каком XID идет речь. Если версия строки все еще существует после более чем двух миллиардов транзакций, она внезапно появится в будущем. Чтобы предотвратить это, QHB резервирует специальный XID, FrozenTransactionId, который не следует нормальным правилам сравнения XID и всегда считается старше любого обычного XID. Версии замороженных строк обрабатываются так, как если бы XID вставки был FrozenTransactionId, так что они будут казаться «в прошлом» для всех обычных транзакций, независимо от проблем с переносом, и поэтому такие версии строк будут действительными до тех пор, пока они не будут удалены, независимо от того, как долго они хранятся.

vacuum_freeze_min_age контролирует, какой возраст должен быть у значения XID, прежде чем строки, содержащие этот XID, будут "заморожены". Увеличение этого параметра поможет избежать ненужной работы, если строки, которые в противном случае были бы заморожены, вскоре будут снова изменены, но уменьшение этого параметра увеличивает количество транзакций, которые могут пройти, прежде чем таблицу необходимо будет снова очистить.

VACUUM использует карту видимости, чтобы определить, какие страницы таблицы необходимо сканировать. Обычно он пропускает страницы, которые не имеют версий "мертвых" строк, даже если на этих страницах все еще могут быть версии строк со старыми значениями XID. Поэтому обычные VACUUM не всегда замораживают каждую старую версию строки в таблице. Периодически VACUUM будет иницировать агрессивный вакуум, пропуская только те страницы, которые не содержат ни пустых строк, ни незамерзших значений XID или MXID. vacuum_freeze_table_age контролирует, когда VACUUM выполнит след. действия: сканируются все видимые, но не полностью замороженные страницы, если количество транзакций, прошедших с момента последнего такого сканирования, больше, чем vacuum_freeze_table_age минус vacuum_freeze_min_age. Установка 0 в vacuum_freeze_table_age заставляет VACUUM использовать эту более агрессивную стратегию для всех сканирований.

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

Подразумевается, что если таблица не будет очищена VACUUM, то для ее обработки будет вызываться autovacuum примерно один раз за autovacuum_freeze_max_age минус vacuum_freeze_min_age транзакцию. Для таблиц, которые регулярно очищает VACUUM в целях освобождения пространства, это не имеет большого значения. Однако для статических таблиц (включая таблицы, для которых вызываются операции вставки, но не обновления и не удаления), нет необходимости в VACUUM для восстановления пространства, поэтому может быть полезно попытаться максимально увеличить интервал между принудительными сеансами автоочистки для очень больших статических таблиц. Очевидно, что это можно сделать, либо увеличив autovacuum_freeze_max_age либо уменьшив vacuum_freeze_min_age.

Сколько-нибудь эффективным максимальным значением vacuum_freeze_table_age является 0.95*autovacuum_freeze_max_age. Большее значение будет упираться в возможный максимум. А значение равное autovacuum_freeze_max_age вообще не имеет смысла, потому что процедура очистки для предотвращения "закольцовывания" (прохода через ноль номера транзакции) запустится к этому моменту сама. Таким образом множитель 0,95 оставляет некоторое пространство для манёвра и запуска VACUUM в ручном режиме, до момента, когда произойдёт закольцовывание. Основным правилом можно считать следующее: Параметр vacuum_freeze_table_age нужно выставить несколько ниже, чем autovacuum_freeze_max_age, оставляя промежуток для штатно-запланированного запуска VACUUM или autovacuum вызываемого нормальными процедурами DELETE и UPDATE. Таким образом, ставя значения слишком близко, возможно повлечь запуск autovacuum для устранения закольцовываний, даже если таблица была недавно очищена для целей восстановления свободного места. Установка же низких значений ведёт к агрессивному и более частому вакуумированию таблицы.

Единственный недостаток увеличения autovacuum_freeze_max_age (и в сочетании с vacuum_freeze_table_age) заключается в том, что подкаталоги pg_xact и pg_commit_ts кластера базы данных будут занимать больше места, поскольку они должны хранить статус фиксации и (если track_commit_timestamp включена) временную метку всех транзакций возрастом меньше чем autovacuum_freeze_max_age. Состояние фиксации использует два бита на транзакцию, поэтому, если для autovacuum_freeze_max_age установлено максимально допустимое значение в два миллиарда, можно ожидать, что pg_xact вырастет примерно до половины гигабайта, а pg_commit_ts - примерно до 20 ГБ. Если это малозначимо по сравнению с вашим общим размером базы данных, рекомендуется установить для autovacuum_freeze_max_age максимально допустимое значение. В противном случае установите его в зависимости от того, что вы хотите разрешить для pg_xact и pg_commit_ts. (Значение по умолчанию, 200 миллионов транзакций, означает около 50 МБ хранилища pg_xact и около 2 ГБ хранилища pg_commit_ts).

Одним из недостатков уменьшения vacuum_freeze_min_age является то, что это может привести к тому, что VACUUM сделает бесполезную работу: замораживания версии строки - пустая трата времени, если строка будет вскоре изменена (что приведет к приобретению строкой нового XID). Таким образом, настройка должна быть достаточно большой, чтобы строки не были заморожены до тех пор, пока они, скорее всего, не изменятся.

Чтобы отследить возраст самых старых незамерзших XID в базе данных, VACUUM сохраняет статистику XID в системных таблицах pg_class и pg_database. В частности, столбец relfrozenxid в строке таблицы pg_class содержит XID отсечки замораживания, который использовался последним агрессивным VACUUM для этой таблицы. Все строки, вставленные транзакциями с XID старше этого XID с отсечкой, гарантированно будут заморожены. Точно так столбец datfrozenxid строки базы данных pg_database является нижней границей незамерзших XID, появляющихся в этой базе данных, — это только минимум значений relfrozenxid каждой таблицы в базе данных. Удобный способ проверить эту информацию - выполнить такие запросы:

SELECT c.oid::regclass as table_name,
       greatest(age(c.relfrozenxid),age(t.relfrozenxid)) as age
FROM pg_class c
LEFT JOIN pg_class t ON c.reltoastrelid = t.oid
WHERE c.relkind IN ('r', 'm');

SELECT datname, age(datfrozenxid) FROM pg_database;

Столбец age показывает количество транзакций от XID среза до XID текущей транзакции.

VACUUM обычно сканирует только те страницы, которые были изменены с момента последнего вакуума, но relfrozenxid может быть расширен только после сканирования каждой страницы таблицы, которая может содержать незамерзщие XID. Это происходит, когда relfrozenxid больше, чем vacuum_freeze_table_age транзакции, когда используется опция FREEZE VACUUM, или когда все страницы, которые еще не полностью заморожены, требуют очистки для удаления версий мертвых строк. Когда VACUUM сканирует каждую страницу в таблице, которая еще не полностью заморожена, ему следует установить значение для age(relfrozenxid) чуть превышающее vacuum_freeze_min_age. Если VACUUM, устанавливающий relfrozenxid, не будет выдан на таблицу до тех пор, пока autovacuum_freeze_max_age не будет достигнут, то для таблицы будет автоматически запущена автоочистка.

Если по какой-то причине автоочистке не удастся удалить старые XID из таблицы, система начнет выдавать предупреждающие сообщения, подобные этому, когда самые старые XID базы данных достигнут десяти миллионов транзакций с точки прохода VACUUM:

WARNING:  database "mydb" must be vacuumed within 177009986 transactions
HINT:  To avoid a database shutdown, execute a database-wide VACUUM in "mydb".

(Ручной VACUUM должен решить проблему, как подсказано в сообщении, но учтите, что VACUUM должен выполняться суперпользователем, иначе он не сможет обрабатывать системные каталоги и, следовательно, не сможет продвигать datfrozenxid базы данных). Если эти предупреждения игнорируются, система завершит работу и откажется начинать любые новые транзакции, если до завершения процедуры останется менее 1 миллиона транзакций:

ERROR:  database is not accepting commands to avoid wraparound data loss in database "mydb"
HINT:  Stop the postmaster and vacuum that database in single-user mode.

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

Мультитранзакции и зацикливание

Идентификаторы мультитранзакций используются для поддержки блокировки строк несколькими транзакциями. Поскольку в заголовке кортежа имеется только ограниченное пространство для хранения информации о блокировке, эта информация кодируется как «идентификатор множественной транзакции» или идентификатор мультитранзакции, когда существует более одной транзакции, одновременно блокирующей строку. Информация о том, какие идентификаторы транзакций включены в любой конкретный идентификатор мультитранзакции, хранится отдельно в подкаталоге pg_multixact, и в поле xmax в заголовке кортежа отображается только идентификатор мультитранзакции. Как и идентификаторы транзакций, идентификаторы мультитранзакций реализованы в виде 32-разрядного счетчика и соответствующего хранилища, что требует тщательного управления устареванием, очистки хранилища и обработки изменений при зацикливаниях. Существует отдельная область хранения, которая содержит список элементов для каждой мультитранзакции, которая также использует 32-разрядный счетчик и которым также необходимо управлять.

Всякий раз, когда VACUUM сканирует какую-либо часть таблицы, он заменяет любой обнаруженный им идентификатор мультитранзакции, который старше, чем vacuum_multixact_freeze_min_age, на другое значение, которое может быть нулевым значением, идентификатором отдельной транзакции или новым идентификатором мультитранзакции. Для каждой таблицы pg_class.relminmxid хранит самый старый из возможных идентификаторов мультитранзакций, которые все еще присутствуют в любом кортеже этой таблицы. Если это значение старше, чем vacuum_multixact_freeze_table_age, агрессивный вакуум запускается принудительно. Как обсуждалось в предыдущем разделе, агрессивный вакуум означает, что будут пропущены только те страницы, про которые известно, что они полностью заморожены. Функция mxid_age() может использоваться для pg_class.relminmxid для определения возраста.

Агрессивное сканирование VACUUM, независимо от того, что его вызывает, позволяет повысить доступность дискового пространства. В конце концов, так как все таблицы во всех базах данных сканируются и их самые старые значения мультитранзакций обновляются, пространство на диске для старых файлов мультитранзакций может быть освобождено.

В качестве защитного устройства агрессивное сканирование VACUUM будет выполняться для любой таблицы, возраст мультитранзакций которой больше, чем autovacuum_multixact_freeze_max_age. Агрессивное VACUUM сканирование также будет происходить постепенно для всех таблиц, начиная с тех, которые имеют самые старые мультитранзакции, если объем используемого пространства хранения элементов превышает 50% адресуемого пространства хранения. Оба этих вида агрессивного сканирования будут происходить даже в том случае, если автоочистка формально отключена.

Процесс «Автовакуум»

QHB имеет необязательную, но настоятельно рекомендуемую функцию, называемую Автовакуум (autovacuum), цель которой - автоматизировать выполнение команд VACUUM и ANALYZE. При включении autovacuum проверяет таблицы, в которые было вставлено, обновлено или удалено большое количество кортежей. Эти проверки используют средства сбора статистики; поэтому, autovacuum нельзя использовать, если для track_counts не установлено значение true. В конфигурации по умолчанию автоочистка включена, и соответствующие параметры конфигурации установлены соответствующим образом.

Процесс autovacuum на самом деле состоит из нескольких процессов. Существует постоянный фоновый процесс, называемый средством запуска autovacuum (autovacuum executor), который отвечает за запуск рабочих процессов autovacuum для всех баз данных. Модуль запуска будет распределять работу по времени, пытаясь запускать по одному процессу в каждой базе данных каждые autovacuum_naptime секунд. (Следовательно, если в установке имеется N баз данных, новый процесс будет запускаться каждые autovacuum_naptime/N секунд). Одновременно разрешено запускать максимум autovacuum_max_workers рабочих процессов. Если запущено больше баз данных, чем установленное значение autovacuum_max_workers, то следующая база данных будет обработана, как только закончится первый процесс. Каждый рабочий процесс будет проверять каждую таблицу в своей базе данных и выполнять VACUUM и/или ANALYZE по мере необходимости. log_autovacuum_min_duration может быть установлен для мониторинга активности процессов автоочистки.

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

Таблицы, у которых значение relfrozenxid больше, чем autovacuum_freeze_max_age старых транзакций, всегда очищаются VACUUM (это также относится к тем таблицам, чей максимальный срок замораживания был изменен с помощью параметров хранилища; см. ниже). В противном случае, если количество кортежей, устаревших с момента последнего VACUUM, превышает «порог», таблица очищается VACUUM. Порог вакуума (vacuum threshold) определяется как:

vacuum threshold = vacuum base threshold + vacuum scale factor * number of tuples

где базовый порог вакуума (vacuum base threshold) - autovacuum_vacuum_threshold, коэффициент масштабирования вакуума (vacuum scale factor)- autovacuum_vacuum_scale_factor, а число кортежей (number of tuples) - pg_class.reltuples. Количество устаревших кортежей котрое получается из сборщика статистики - это примерный расчет, обновляемый каждой операцией UPDATE и DELETE. (Расчет приблизительный, потому, что некоторая информация может быть потеряна при большой нагрузке). Если значение relfrozenxid в таблице больше, чем vacuum_freeze_table_age транзакции, агрессивный вакуум выполняется для замораживания старых кортежей и продвижения relfrozenxid, в противном случае сканируются только страницы, которые были изменены с момента последнего вакуума.

Для анализа используется аналогичное условие: порог, определяемый как:

analyze threshold = analyze base threshold + analyze scale factor * number of tuples

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

Временные таблицы не доступны для автоочистки. Следовательно, соответствующие операции вакуума и анализа для них должны выполняться с помощью команд сеанса SQL.

Пороговые значения по умолчанию и масштабные коэффициенты взяты из qhb.conf, но их можно переопределить (и многие другие параметры управления автоочисткой) для каждой таблицы; см. Параметры хранения для получения дополнительной информации. Если параметр управляющий autovacuum был изменен с помощью параметров хранения таблицы, это значение используется при обработке этой таблицы - в противном случае используются глобальные настройки. См. раздел Автоматическая очистка для более подробной информации о глобальных настройках.

Когда работают несколько процессов autovacuum, параметры задержки затрат на автоочистку (см. раздел Определение предела стоимости работы процесса очистки) «сбалансированы» между всеми работающими процессами, так что общее влияние ввода/вывода на систему одинаково независимо от количества фактически работающих процессов, Однако любые рабочие таблицы, для которых были установлены собственные параметры хранения autovacuum_vacuum_cost_delay или autovacuum_vacuum_cost_limit, не учитываются в алгоритме балансировки.

Процессы autovacuum обычно не блокируют другие команды. Если процесс попытается получить блокировку, которая конфликтует с блокировкой SHARE UPDATE EXCLUSIVE удерживаемой автоочисткой, получение блокировки прервет autovacuum. Конфликтующие режимы блокировки см. в таблице. Однако, если автоочистка работает для предотвращения закольцовывания идентификатора транзакции (т. е. имя запроса автоочистки в представлении pg_stat_activity заканчивается текстом to prevent wraparound), автоочистка автоматически не прерывается.

Предупреждение!!!
Регулярно выполняемые команды, которые получают блокировки, конфликтующие с блокировкой SHARE UPDATE EXCLUSIVE (например, ANALYZE), могут эффективно предотвращать завершение autovacuum.

Регулярная переиндексация

В некоторых ситуациях целесообразно периодически перестраивать индексы с помощью команды REINDEX или ряда отдельных шагов перестройки.

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

Потенциал раздувания (bloat) в индексах отличных от B-tree не был достаточно исследован. Рекомендуется периодически отслеживать физический размер индекса при использовании любого типа индекса, отличного от B-tree.

Кроме того, для индексов B-tree доступ к недавно сконструированному индексу немного быстрее, чем к индексу, который много раз обновлялся, потому что логически смежные страницы обычно также физически соседствуют во вновь созданном индексе. (Это соображение не относится к индексам, не относящимся к B-tree). Возможно, есть смысл периодически переиндексировать таблицы для повышения скорости доступа.

REINDEX может использоваться легко и безопасно во всех случаях. Эта команда требует блокировки ACCESS EXCLUSIVE по умолчанию, поэтому часто предпочтительно выполнять ее с параметром CONCURRENTLY, который требует только блокировки SHARE UPDATE EXCLUSIVE.

Обслуживание файла журнала

Хорошей идеей будет сохранить куда-нибудь вывод журнала сервера базы данных, а не просто отбрасывать его через /dev/null. Вывод журнала очень важен при диагностике проблем. Однако вывод журнала имеет тенденцию к росту объемов (особенно на более высоких уровнях детализации), поэтому его нет смысла сохранять его бесконечно долго. Желательно настроить файлы журнала так, чтобы новые файлы журнала запускались, а старые удалялись через разумный период времени.

Если вы просто направите stderr процесса qhb в файл, у вас будет вывод журнала, но единственный способ обрезать файл журнала — это остановить и перезапустить сервер. Это может быть приемлемо, если вы используете QHB в среде разработки, но немногие продукционные серверы сочтут это поведение приемлемым.

Лучшим подходом является отправка вывода stderr сервера в какую-либо программу ротации журналов. Существует встроенная logging_collector ротации журналов, которую вы можете использовать, установив для параметра конфигурации logging_collector значение true в qhb.conf. Параметры управления для этой программы описаны в разделе Расположение журнала. Вы также можете использовать этот подход для захвата данных журнала в машиночитаемом формате CSV (значения, разделенные запятыми).

В качестве альтернативы вы можете использовать внешнюю программу ротации журналов, если у вас есть такая, которую вы уже используете с другим серверным программным обеспечением. Например, инструмент rotatelogs, включенный в дистрибутив Apache, может использоваться с QHB. Один из способов сделать это - направить вывод сервера stderr в нужную программу. Если вы запускаете сервер с qhb_ctl, то stderr уже перенаправлен на stdout, поэтому вам просто нужна команда pipe, например:

qhb_ctl start | rotatelogs /var/log/pgsql_log 86400

Вы можете объединить эти подходы, настроив logrotate для сбора файлов журналов, создаваемых встроенным сборщиком журналов QHB. В этом случае сборщик журналов определяет имена и расположение файлов журналов, а logrotate периодически архивирует эти файлы. При запуске ротации журнала logrotate должен убедиться, что приложение отправляет дальнейшие выходные данные в новый файл. Обычно это делается с помощью сценария postrotate который отправляет сигнал SIGHUP приложению, которое затем повторно открывает файл журнала. В QHB вы можете запустить qhb_ctl с опцией logrotate. Когда сервер получает эту команду, сервер либо переключается на новый файл журнала, либо повторно открывает существующий файл, в зависимости от конфигурации ведения журнала (см. Раздел Расположение журнала).

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

Другой производственный подход к управлению выводом журнала - отправить его в системный журнал и позволить системному журналу работать с ротацией файлов. Для этого установите для параметра конфигурации log_destination значение syslog (для вывода только в syslog) в qhb.conf. Затем вы можете отправить сигнал SIGHUP демону syslog всякий раз, когда вы хотите заставить его начать запись нового файла журнала. Если вы хотите автоматизировать ротацию журналов, программа logrotate может быть настроена для работы с файлами журналов на системном уровне.

Однако во многих установках системный журнал не очень надежен, особенно с большими сообщениями, он может обрезать или отбрасывать сообщения именно тогда, когда они вам нужны больше всего. Кроме того, в Linux системный журнал сбрасывает каждое сообщение на диск, что приводит к снижению производительности. (Вы можете использовать «-» в начале имени файла в файле конфигурации системного журнала, чтобы отключить синхронизацию).

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