pg_repack

pg_repack — утилита и расширение QHB для реорганизации таблиц

Синтаксис

pg_repack [параметр...] [имя_бд]

Описание

pg_repack — это расширение QHB, которое позволяет избавляться от «разбухания» таблиц и индексов и при необходимости восстанавливать физический порядок кластеризованных индексов. В отличие от команд CLUSTER и VACUUM FULL, оно делает это в реальном времени, не удерживая эксклюзивную блокировку таблиц во время их обработки. Кроме того, pg_repack очень эффективно, его производительность сравнима с прямым использованием CLUSTER.

Для реорганизации таблиц можно выбрать один из следующих способов:

  • Выполнение в режиме реального времени команды CLUSTER (упорядочивание по кластерному индексу);
  • Упорядочивание по указанным столбцам;
  • Выполнение в режиме реального времени команды VACUUM FULL (упаковка только строк);
  • Перестройка или перемещение только индексов таблицы.

Примечание
Использовать эту утилиту могут только суперпользователи либо владельцы таблиц и индексов. Чтобы выполнить pg_repack от имени такого владельца, нужно воспользоваться параметром --no-superuser-check.

Примечание
Целевая таблица должна иметь первичный ключ (PRIMARY KEY) или хотя бы уникальный общий индекс (UNIQUE) для столбца NOT NULL.


Требования

Версия QHB 1.5.1 и выше.

Диски: Для полной перепаковки таблиц требуется свободное место на диске размером примерно в два раза больше, чем занимает целевая таблица (или таблицы) и ее индексы. Например, если общий размер реорганизуемых таблиц и индексов составляет 1 ГБ, потребуется дополнительно 2 ГБ дискового пространства.


Установка

Модуль реорганизации таблиц с минимальными блокировками для QHB поставляется в виде пакета qhb-1.5.2-pg-repack.

Подключите репозиторий пакетов QHB и установите пакет расширения для выбранной платформы со страницы загрузки.

После установки загрузите расширение pg_repack в базу данных, которую необходимо обработать. Модуль pg_repack упакован как расширение, поэтому можно выполнить:

$ psql -c "CREATE EXTENSION pg_repack" -d ваша_бд

Удалить pg_repack можно с помощью команды DROP EXTENSION pg_repack или просто удалив схему repack.

При обновлении с предыдущей версии pg_repack просто удалите старую версию из базы данных, как описано выше, и установите новую версию.


Параметры

Параметры реорганизации

-a
--all
Попытаться перепаковать все базы данных кластера. Базы данных, в которых не установлено расширение pg_repack, будут пропущены.

-t таблица
--table=таблица
Реорганизовать только указанную таблицу. Реорганизовать несколько таблиц можно, написав несколько ключей -t. По умолчанию реорганизуются все подходящие таблицы в целевых базах данных.

-I таблица
--parent-table=таблица Реорганизовать как указанную таблицу, так и ее потомков. Реорганизовать несколько деревьев иерархии наследования можно, написав несколько ключей -I.

-c схема
--schema=схема
Перепаковать таблицы только в указанной схеме. Перепаковать несколько схем можно, написав несколько ключей -c. Можно использовать вместе с --tablespace для перемещения таблиц в другое табличное пространство.

-o столбец[,...]
--order-by=столбец[,...]
Выполнить неблокирующую кластеризацию (CLUSTER) с упорядочиванием по указанным столбцам.

-n
--no-order
Выполнить неблокирующую полную очистку (VACUUM FULL). Это значение по умолчанию для некластеризованных таблиц.

-N
--dry-run
Показать, что будет перепаковано, и завершиться.

-j число_подключений
--jobs=число_подключений
Создать указанное количество дополнительных подключений к QHB и использовать эти дополнительные подключения для распараллеливания перестройки индексов для каждой таблицы. Параллельное построение индексов поддерживается только для полной перепаковки таблиц, без параметров --index или --only- indexes. Если на сервере QHB есть дополнительные ядра и дисковый ввод-вывод, это может быть полезным способом ускорить pg_repack.

-s табличное_пространство
--tablespace=табличное_пространство
Переместить перепакованные таблицы в указанное табличное пространство: по сути это неблокирующая версия ALTER TABLE ... SET TABLESPACE. Индексы таблиц остаются в исходном табличном пространстве, если только дополнительно не указан параметр --moveidx.

-S
--moveidx
Переместить индексы перепакованных таблиц в табличное пространство, указанное в параметре --tablespace.

-i индекс
--index=индекс
Перепаковать только указанный индекс. Перепаковать несколько индексов можно, написав несколько ключей -i. Может использоваться вместе с параметром --tablespace для перемещения индексов в другое табличное пространство.

-x
--only-indexes
Перепаковать только индексы таблицы (таблиц), указанной в параметре --table или --parent-table.

-T сек
--wait-timeout=сек
Расширению pg_repack нужно получить эксклюзивную блокировку в конце реорганизации. Этот параметр определяет, сколько секунд pg_repack будет ждать, чтобы получить эту блокировку. Если блокировку не удастся получить по истечении этого времени и параметр --no-kill-backend не указан, pg_repack принудительно отменит конфликтующие запросы. pg_repack прибегнет к вызову pg_terminate_backend() для отключения всех оставшихся серверных процессов, после того как этот срок пройдет дважды. Значение по умолчанию — 60 секунд.

-D
--no-kill-backend
Если блокировка не была снята за время, указанное в --wait-timeout, вместо отмены конфликтующих запросов перейти к перепаковке таблицы. Значение по умолчанию — false.

-Z
--no-analyze
Не выполнять ANALYZE после полной реорганизации таблицы. Если этот ключ не указан, после реорганизации выполняется ANALYZE.

-k
--no-superuser-check
Пропустить проверки суперпользователя на стороне клиента. Этот параметр полезен для использования pg_repack на платформах, поддерживающих запуск от имени пользователя без прав суперпользователя.

-C
--exclude-extension
Не перепаковывать таблицы, принадлежащие конкретному расширению. Некоторые расширения могут сильно зависеть от таких таблиц во время планирования и т. д.

--no-error-on-invalid-index
Провести перепаковку, даже если найден нерабочий индекс.

--error-on-invalid-index
Не проводить перепаковку, если найден нерабочий индекс (считается устаревшим, поскольку теперь это поведение по умолчанию).

--apply-count=число_кортежей
Количество кортежей, которые будут применяться в одной транзакции при воспроизведении.

--switch-threshold=число_кортежей
Переставить таблицы, когда в таблице журнала осталось это количество кортежей. Этот параметр можно использовать во избежание трудностей с наверстыванием таблиц с интенсивной записью данных.


Параметры подключения

Параметры для подключения к серверам. Параметры -all и --dbname, или --table, или --parent-table нельзя использовать одновременно.

-a
--all
Реорганизовать все базы данных.

-d имя_бд
--dbname=имя_бд
Задает имя реорганизуемой базы данных. Если этот параметр не указан и не используется параметр -a (или --all), имя базы данных считывается из переменной среды PGDATABASE. Если этот параметр не установлен, используется имя пользователя, указанное для подключения.

-h хост
--host=хост
Указывает имя хост-компьютера, на котором работает сервер. Если значение начинается со слэша, оно используется в качестве каталога для сокета домена Unix.

-p порт
--port=порт
Указывает TCP-порт или расширение файла локального сокета домена Unix, через который сервер принимает подключения.

-U имя_пользователя
--username=имя_пользователя
Имя пользователя, под которым производится подключение.

-w
--no-password
Никогда не запрашивать ввод пароля. Если серверу требуется аутентификация по паролю, и пароль недоступен с помощью иных средств, таких как файл .pgpass, попытка подключения завершится неудачно. Этот параметр может быть полезен в пакетных заданиях и скриптах, где нет пользователя, чтобы ввести пароль.

-W
--password
Принудительно запрашивать пароль перед подключением к базе данных.
Это несущественный параметр, так как pg_repack автоматически запросит пароль, если сервер требует аутентификацию по паролю. Однако чтобы выяснить это, pg_repack потребуется дополнительная попытка подключения к серверу. В некоторых случаях имеет смысл ввести -W, чтобы исключить эту лишнюю попытку.


Общие параметры

-e
--echo
Отобразить на экране команды, которые pg_repack генерирует и отправляет на сервер.

-E уровень
--elevel=уровень
Выбрать уровень выводимых сообщений: DEBUG, INFO, NOTICE, WARNING, ERROR, LOG, FATAL и PANIC. Уровень по умолчанию — INFO.

--help
Показать справку об аргументах командной строки pg_repack и завершиться.

--version
Вывести версию pg_repack и завершиться.


Переменные среды

PGDATABASE
PGHOST
PGPORT
PGUSER
Параметры подключения по умолчанию.

Эта утилита, как и большинство других утилит QHB, также использует переменные среды, поддерживаемые libpq (см. раздел Переменные среды).


Примеры

Выполнить неблокирующую команду CLUSTER всех кластеризованных таблиц в базе данных test и выполнить неблокирующую команду VACUUM FULL всех некластеризованных таблиц:

$ pg_repack test

Выполнить неблокирующую команду VACUUM FULL для таблиц foo и bar в базе данных test (итоговый кластерный индекс игнорируется):

$ pg_repack --no-order --table foo --table bar test

Переместить все индексы таблицы foo в табличное пространство tbs:

$ pg_repack -d test --table foo --only-indexes --tablespace tbs

Переместить указанный индекс в табличное пространство tbs:

$ pg_repack -d test --index idx --tablespace tbs

Диагностика

При сбое pg_repack выводятся сообщения об ошибках. В следующем списке показаны причины ошибок.

После фатальных ошибок потребуется очистка вручную. Для этого просто удалите pg_repack из базы данных и заново его установите. Выполните

DROP EXTENSION pg_repack CASCADE

в базе данных, где произошла ошибка, а затем выполните

CREATE EXTENSION pg_repack
INFO: database "db" skipped: pg_repack VER is not installed in the database
-- ИНФО: база данных "db" пропущена: В этой базе данных не установлено pg_repack VER

Если указан параметр --all, pg_repack в базе данных не устанавливается.

Создайте расширение pg_repack в базе данных.

ERROR: pg_repack VER is not installed in the database
-- ОШИБКА: в этой базе данных не установлено pg_repack VER

pg_repack не установлено в базе данных, указанной в параметре --dbname.

Создайте расширение pg_repack в базе данных.

ERROR: program 'pg_repack V1' does not match database library 'pg_repack V2'
-- ОШИБКА: программа 'pg_repack V1' не соответствует библиотеке базы данных 'pg_repack V2'

Существует несоответствие между двоичным файлом pg_repack и библиотекой базы данных (.so или .dll).

Несоответствие может быть связано с неправильным двоичным файлом в $PATH или обращением к неправильной базе данных. Проверьте каталог программы и базу данных; если они соответствуют ожиданиям, возможно, вам потребуется повторить установку pg_repack.

ERROR: extension 'pg_repack V1' required, found 'pg_repack V2'
-- ОШИБКА: требуется расширение 'pg_repack V1', найдено 'pg_repack V2'

Расширение SQL, найденное в базе данных, не соответствует версии, требуемой программой pg_repack.

Необходимо удалить расширение из базы данных и перезагрузить его, как описано в параграфе Установка.

ERROR: relation "table" must have a primary key or not-null unique keys
-- ОШИБКА: отношение "table" должно иметь первичный ключ или уникальные ключи, отличные от NULL

Для целевой таблицы не определено ограничение PRIMARY KEY или какие-либо ограничения UNIQUE.

Определите для таблицы ограничение PRIMARY KEY или UNIQUE.

ERROR: query failed: ERROR: column "col" does not exist
-- ОШИБКА: запрос не выполнен: ОШИБКА: столбец "col" не существует

В целевой таблице нет столбцов, указанных в параметре --order-by.

Укажите существующие столбцы.

WARNING: the table "tbl" already has a trigger called repack_trigger
-- ПРЕДУПРЕЖДЕНИЕ: у таблицы "tbl" уже имеется триггер с именем repack_trigger

Этот триггер, вероятно, был установлен во время предыдущей попытки запуска pg_repack для таблицы, которая была прервана и по какой-то причине не смогла удалить временные объекты.

Удалить все временные объекты можно, удалив и заново создав расширение: подробную информацию см. в параграфе Установка.

WARNING: trigger "trg" conflicting on table "tbl"
-- ПРЕДУПРЕЖДЕНИЕ: триггер "trg" конфликтует с таблицей "tbl"

У целевой таблицы имеется триггер, имя которого идет за z_repack_trigger в алфавитном порядке.

z_repack_trigger должен быть последним срабатывающим триггером BEFORE. Переименуйте свой триггер, чтобы по алфавиту он шел перед триггером pg_repack; для этого можно выполнить:

ALTER TRIGGER zzz_my_trigger
 ON sometable RENAME TO yyy_my_trigger;
ERROR: Another pg_repack command may be running on the table. Please try again later.
-- ОШИБКА: Возможно, для этой таблицы уже выполняется другая команда pg_repack.
-- Пожалуйста, повторите попытку позднее.

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

WARNING: Cannot create index "schema"."index_xxxx", already exists
DETAIL: An invalid index may have been left behind by a previous pg_repack on the
table which was interrupted. Please use DROP INDEX "schema"."index_xxxxx" to remove
this index and try again.
-- ПРЕДУПРЕЖДЕНИЕ: Невозможно создать уже существующий индекс "schema"."index_xxxx"
-- ПОДРОБНЕЕ: Недопустимый индекс мог быть оставлен при предыдущем выполнении
-- pg_repack для таблицы, которое было прервано. Пожалуйста, воспользуйтесь
-- DROP INDEX "schema"."index_xxxxx", чтобы удалить этот индекс, и повторите попытку.

Был оставлен временный индекс, явно созданный при предыдущем выполнении pg_repack, и не стоит рисковать, удаляя его самостоятельно. Если этот индекс действительно был создан при предыдущем запуске pg_repack, после которого не была проведена очистка, следует просто выполнить DROP INDEX и повторить команду repack.


Ограничения

Расширение pg_repack имеет следующие ограничения:

  • pg_repack не может реорганизовать временные таблицы.

  • pg_repack не может кластеризовать таблицы по индексам GiST.

  • Пока выполняется pg_repack, вы не сможете выполнять команды DDL для целевых таблиц, за исключением VACUUM или ANALYZE. Чтобы обеспечить соблюдение этого ограничения, pg_repack будет удерживать блокировку ACCESS SHARE для целевой таблицы во время ее полной перепаковки.


Детализация

Полная перепаковка таблицы

Чтобы выполнить полную перепаковку таблицы, pg_repack:

  1. создает таблицу журнала для записи изменений, внесенных в исходную таблицу;
  2. добавляет триггер в исходную таблицу для регистрации команд INSERT, UPDATE и DELETE в таблице журнала;
  3. создает новую таблицу, содержащую все строки из старой таблицы;
  4. строит индексы в этой новой таблице;
  5. применяет все изменения, которые произошли в таблице журнала, к новой таблице;
  6. переставляет таблицы, включая индексы и таблицы TOAST, используя системные каталоги;
  7. удаляет исходную таблицу.

pg_repack будет удерживать блокировку ACCESS EXCLUSIVE только в течение короткого периода времени во время первоначальной настройки (шаги 1 и 2) и на заключительном этапе перестановки и удаления (шаги 6 и 7). В остальное время pg_repack нужно удерживать только блокировку ACCESS SHARE для исходной таблицы, что означает, что операции INSERT, UPDATE и DELETE могут выполняться как обычно.


Перепаковка только индексов

Чтобы выполнить перепаковку только для индекса, pg_repack проводит следующие операции:

  1. создает новые индексы в таблице, используя неблокирующее (CONCURRENTLY) сопоставление определений старых индексов;
  2. заменяет в каталогах старые индексы на новые;
  3. удаляет старые индексы.

Неблокирующее создание индексов осуществляется с несколькими оговорками; подробную информацию см. в параграфе Неблокирующее построение индексов на справочной странице команды CREATE INDEX.


См. также

Документация по pg_repack на Github, clusterdb, vacuumdb