[Документация Yandex Cloud](../../../index.md) > [Yandex Managed Service for PostgreSQL](../../index.md) > [Пошаговые инструкции](../index.md) > Расширения и словари PostgreSQL > pg_repack

# Использование pg_repack в Managed Service for PostgreSQL

Таблицы и индексы PostgreSQL могут быть подвержены _раздуванию_ (bloating). При выполнении транзакций, которые изменяют данные в таблицах и индексах, старая версия данных сохраняется, чтобы можно было откатить транзакции, если это потребуется (rollback). Это приводит к тому, что таблицы и индексы раздуваются в размере при массовом изменении данных. Оценить степень раздувания можно, например, с помощью расширения [pgstattuple](cluster-extensions.md#postgresql) или набора запросов [pgsql-bloat-estimation](https://github.com/ioguix/pgsql-bloat-estimation).

Старые версии данных не удаляются автоматически. Если они больше не нужны, то можно удалить их, чтобы освободить занятое ими хранилище и устранить раздувание (bloat). Для этого обычно используются команды [VACUUM FULL](https://www.postgresql.org/docs/current/sql-vacuum.html) или [CLUSTER](https://www.postgresql.org/docs/current/sql-cluster.html). Однако эти команды требуют эксклюзивной блокировки таблиц на все время выполнения, что не всегда удобно или допустимо.

Расширение [pg_repack](https://github.com/reorg/pg_repack) позволяет перепаковывать (repack) таблицы и индексы, чтобы устранить их раздувание. В отличие от других методов, `pg_repack` устанавливает эксклюзивную блокировку таблицы на короткий промежуток времени. Подробнее на [странице расширения](https://reorg.github.io/pg_repack/).

## Установить расширение pg_repack в кластер PostgreSQL {#install-extension}

1. [Добавьте расширение](cluster-extensions.md#update-extensions) `pg_repack` к выбранной базе данных.

1. [Назначьте владельцу этой базы данных](../grant.md#grant-role) роль `mdb_admin`, если это еще не сделано.

    Имя владельца можно запросить со [списком баз данных в кластере](../databases.md#list-db).

1. [Задайте нулевые значения](../update.md#change-postgresql-config) для следующих настроек кластера PostgreSQL:

    * [statement_timeout](../../concepts/settings-list.md#setting-statement-timeout);
    * [idle_in_transaction_session_timeout](../../concepts/settings-list.md#setting-idle-session-timeout).

    {% note warning %}

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

    {% endnote %}

## Установить клиент pg_repack {#install-client}

Для работы с расширением используется одноименный клиент. Клиент устанавливается на хост, с которого есть возможность [подключения к кластеру PostgreSQL](../connect/index.md).

Чтобы установить клиент:

1. [Определите версию расширения](cluster-extensions.md#postgresql) `pg_repack`, которая установлена в кластер PostgreSQL.
1. [Установите клиент](https://reorg.github.io/pg_repack/#installation) `pg_repack`.

    {% note warning %}

    Версии клиента и расширения должны совпадать, иначе подключение завершится с ошибкой:

    ```text
    ERROR: pg_repack failed with error: program 'pg_repack ...' does not match database library 'pg_repack ...'
    ```

    {% endnote %}

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

    {% cut "Инструкция по сборке клиента pg_repack в Ubuntu 22.04 LTS" %}

    1. Подключите [Apt-репозиторий PostgreSQL](https://wiki.postgresql.org/wiki/Apt), который содержит часть зависимостей, необходимых для сборки:

        ```bash
        sudo apt install -y postgresql-common && \
        sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -y $(lsb_release -cs)
        ```

    1. Установите зависимости.

        Выберите версию пакета `postgresql-server-dev-*`, совпадающую с версией кластера PostgreSQL, к которому планируется подключаться с помощью клиента. Это повысит стабильность работы собранного клиента.

        Пример команды, которая устанавливает упомянутый пакет для PostgreSQL 16, а также другие пакеты:

        ```bash
        sudo apt install git build-essential \
                         zlib1g-dev libzstd-dev liblz4-dev \
                         libreadline-dev \
                         postgresql-server-dev-16
        ```

    1. Клонируйте Git-репозиторий `pg_repack`, выбрав [тег для нужной версии](https://github.com/reorg/pg_repack/tags), и перейдите в локальную директорию с репозиторием.

        Пример команды для тега `ver_1.4.8`:

        ```bash
        git clone https://github.com/reorg/pg_repack.git \
            --branch ver_1.4.8 --depth 1 && \
        cd pg_repack
        ```

    1. Запустите сборку:

        ```bash
        make
        ```

        Дождитесь окончания процесса сборки.

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

        Пример команды для перемещения в `/usr/local/bin`:

        ```bash
        sudo install bin/pg_repack /usr/local/bin
        ```

    1. Проверьте версию клиента:

        ```bash
        pg_repack --version
        ```

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

        ```text
        pg_repack 1.4.8
        ```

    {% endcut %}

## Запустить pg_repack {#run}

{% note tip %}

Запускайте `pg_repack`, когда нагрузка на кластер PostgreSQL минимальна: процесс перепаковки объектов базы данных создает дополнительную нагрузку на кластер.

Данные о [состоянии кластера и его хостов](../monitoring.md) доступны в консоли управления.

{% endnote %}

Чтобы запустить `pg_repack` для перепаковки объектов базы данных:

1. [Убедитесь, что в кластере достаточно свободного места в хранилище](../monitoring.md#monitoring-cluster): минимум в два раза больше суммарного объема таблиц и индексов, которые будут перепаковываться.

    В ходе своей работы `pg_repack` оперирует копиями таблиц и индексов, поэтому ему необходимо дополнительное место для выполнения перепаковки.

1. Запустите клиент `pg_repack` с нужными параметрами.

    Ниже приведены команды для запуска клиента с распространенными комбинациями параметров. Описание всех поддерживаемых параметров на [странице расширения](https://reorg.github.io/pg_repack/).

    {% note tip %}

    Добавьте параметр `--dry-run`, чтобы запустить `pg_repack` в режиме пробного запуска и оценить планируемые изменения.

    Будет выведен список объектов, которые будут перепакованы при запуске `pg_repack` в обычном режиме.

    {% endnote %}

    Выполните нужную команду:

    * Команда для перепаковки указанных таблиц в базе данных:

        {% list tabs group=connection %}

        - Перепаковка с подключением без SSL {#without-ssl}

            ```bash
            pg_repack -k -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
                      -U <имя_пользователя> \
                      -d <имя_базы_данных> \
                      -t <имя_таблицы>
            ```

        - Перепаковка с подключением по SSL {#with-ssl}

            ```bash
            PGSSLMODE='verify-full' \
            pg_repack -k -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
                      -U <имя_пользователя> \
                      -d <имя_базы_данных> \
                      -t <имя_таблицы>
            ```

        {% endlist %}

        Если нужно перепаковать несколько таблиц, то передайте нужное количество параметров `-t` — по одному на таблицу.

    * Команда для перепаковки указанных индексов в базе данных:

        {% list tabs group=connection %}

        - Перепаковка с подключением без SSL {#without-ssl}

            ```bash
            pg_repack -k -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
                      -U <имя_пользователя> \
                      -d <имя_базы_данных> \
                      -i <имя_индекса>
            ```

        - Перепаковка с подключением по SSL {#with-ssl}

            ```bash
            PGSSLMODE='verify-full' \
            pg_repack -k -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
                      -U <имя_пользователя> \
                      -d <имя_базы_данных> \
                      -i <имя_индекса>
            ```

        {% endlist %}

        Если нужно перепаковать несколько индексов, то передайте нужное количество параметров `-i` — по одному на индекс.

    * Команда для перепаковки всех таблиц и индексов в базе данных:

        {% list tabs group=connection %}

        - Перепаковка с подключением без SSL {#without-ssl}

            ```bash
            pg_repack -k -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
                      -U <имя_пользователя> \
                      -d <имя_базы_данных>
            ```

        - Перепаковка с подключением по SSL {#with-ssl}

            ```bash
            PGSSLMODE='verify-full' \
            pg_repack -k -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
                      -U <имя_пользователя> \
                      -d <имя_базы_данных>
            ```

        {% endlist %}

## Пример использования {#usage-example}

{% note info %}

Пример проверялся в следующем окружении:

* Кластер PostgreSQL версии `16`, в котором:

    * [Создана база данных](../databases.md#add-db) `db1`, владелец базы — `user1`.
    * В базу данных `db1` [установлено расширение](#install-extension) `pg_repack` версии `1.5.2`.

* Виртуальная машина Yandex Cloud с Ubuntu 22.04 LTS, в которой:

    * [Установлен собранный из исходных файлов клиент](#install-client) `pg_repack` версии `1.5.2`.
    * [Есть возможность подключения к кластеру](../connect/index.md) по [SSL](../connect/index.md#get-ssl-cert).

{% endnote %}

В этом примере используется инструмент [pgbench](https://www.postgresql.org/docs/current/pgbench.html), который предназначен для нагрузочного тестирования PostgreSQL и позволяет в автоматическом режиме выполнять следующие операции:

* Создавать тестовые таблицы и индексы, наполнять таблицы тестовыми данными.
* Выполнять множество запросов к тестовым таблицам, включая запросы `INSERT` и `DELETE`, которые изменяют содержимое таблицы.

После завершения работы `pgbench` тестовые таблицы и соответствующие им индексы находятся в раздутом состоянии из-за того, что выполнялось множество запросов. При этом команда `VACUUM`, которая устраняет раздувание таблиц и индексов, выполняется `pgbench` не в конце работы, а в начале. Поэтому `pgbench` будет использован для создания раздутых таблиц и индексов, чтобы продемонстрировать работу `pg_repack`.

Чтобы проверить работу `pg_repack` на тестовых таблицах и индексах `pgbench`:

1. [Получите идентификатор кластера PostgreSQL](../cluster-list.md#list-clusters).

1. [Добавьте расширение](cluster-extensions.md#update-extensions) `pgstattuple` к базе данных `db1`.

    С помощью расширения можно оценить степень раздувания таблиц и индексов, что позволит наглядно продемонстрировать работу `pg_repack`.

1. Установите `pgbench` на виртуальную машину:

    ```bash
    sudo apt install postgresql-contrib
    ```

    {% note info %}

    Пакет `postgresql-contrib` содержится в Apt-репозитории PostgreSQL.

    Если вы удалили этот репозиторий из виртуальной машины после [сборки клиента](#install-client) `pg_repack` в Ubuntu 22.04 LTS — снова подключите репозиторий.

    {% endnote %}

1. Создайте тестовые таблицы и индексы в базе данных `db1`, подключившись к ней от имени владельца `user1`:

    ```bash
    PGSSLMODE='verify-full' \
    pgbench -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
            -U user1 -i -s 1 db1
    ```

    Будут созданы следующие таблицы и индексы:

    | Таблица | Индекс |
    | ------- | ------ |
    | `pgbench_accounts` | `pgbench_accounts_pkey` |
    | `pgbench_branches` | `pgbench_branches_pkey` |
    | `pgbench_tellers`  | `pgbench_tellers_pkey`  |
    | `pgbench_history`  | —                       |

1. Посмотрите статистику для таблиц и индексов `pgbench_*`:

    1. [Подключитесь к базе данных](../connect/clients.md#bash) `db1` от имени владельца `user1`. Для подключения используйте утилиту `psql`.

    1. Запросите статистику по таблицам:

        ```sql
        SELECT * FROM pgstattuple('pgbench_accounts');
        SELECT * FROM pgstattuple('pgbench_branches');
        SELECT * FROM pgstattuple('pgbench_tellers');
        SELECT * FROM pgstattuple('pgbench_history');
        ```

    1. Запросите статистику по индексам:

        ```sql
        SELECT * FROM pgstattuple('pgbench_accounts_pkey');
        SELECT * FROM pgstattuple('pgbench_branches_pkey');
        SELECT * FROM pgstattuple('pgbench_tellers_pkey');
        ```

    В столбцах `dead_tuple_count` должно быть нулевое значение для всех результатов запросов. Это означает, что таблицы и индексы не раздуты.

    > **Пример части вывода для таблицы pgbench_accounts:**
    >
    > ```sql
    >  table_len | tuple_count | ... | dead_tuple_count | ... | free_space | free_percent
    > -----------+-------------+-...-+------------------+-...-+------------+--------------
    >   13434880 |      100000 | ... |                0 | ... |     188960 |         1.41
    > ```

1. Однократно запустите `pgbench`:

    ```bash
    PGSSLMODE='verify-full' \
    pgbench -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
            -U user1 -c 5 -j 2 -t 1000 db1
    ```

    Дождитесь завершения работы `pgbench`, это может занять несколько минут.

1. Повторно посмотрите статистику для таблиц и индексов `pgbench_*`.

    Ненулевые значения в столбцах `dead_tuple_count` свидетельствуют о раздувании таблиц и индексов. В случае тестовых таблиц и индексов, созданных `pgbench`, наибольшее раздувание будет наблюдаться у таблицы `pgbench_tellers`.

1. Запустите `pg_repack` в режиме пробного запуска (dry run), чтобы оценить планируемые изменения:

    ```bash
    PGSSLMODE='verify-full' \
    pg_repack -k -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
              -U user1 \
              -d db1 \
              --dry-run
    ```

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

    > **Пример вывода:**
    >
    > ```text
    > INFO: repacking table "public.pgbench_accounts"
    > INFO: repacking table "public.pgbench_branches"
    > INFO: repacking table "public.pgbench_tellers"
    > ```

1. Запустите `pg_repack` в обычном режиме, чтобы перепаковать таблицы и индексы:

    ```bash
    PGSSLMODE='verify-full' \
    pg_repack -k -h c-<идентификатор_кластера>.rw.mdb.yandexcloud.kz -p 6432 \
              -U user1 \
              -d db1
    ```

    Дождитесь завершения работы `pg_repack`, это может занять несколько минут.

1. Повторно посмотрите статистику для таблиц и индексов `pgbench_*`.

    В столбцах `dead_tuple_count` должно быть нулевое значение для всех результатов запросов. Это означает, что таблицы и индексы не раздуты, и `pg_repack` выполнил работу корректно.