F.49. pg_ilm — Управление жизненным циклом информации#

F.49. pg_ilm — Управление жизненным циклом информации

F.49. pg_ilm — Управление жизненным циклом информации #

Версия: 1.0

F.49.1. Обзор #

pg_ilm — расширение управления жизненным циклом данных для Tantor SE, предназначенное для вычисления рекомендаций по архивированию для обычных таблиц и партиций (leaf partitions).

Рекомендации формируются на основе:

  • Физического состояния хранения

  • Уровня активности (write-нагрузки)

  • Конфигурации правил архивирования

Расширение разделяет процесс на три независимых уровня:

  1. Политика жизненного цикла (rules).

  2. Вычисление следующего допустимого перехода (recommendation).

  3. Физическое исполнение через pg_archive.

Такое разделение обеспечивает детерминированное, объяснимое и пошаговое изменение состояния данных без выполнения неявных или комплексных операций.

F.49.2. Обоснование #

Переходы между состояниями хранения зависят не только от логических правил, но и от физических характеристик таблиц:

  • Фактический tablespace.

  • Текущий access method (heap или columnar).

  • Тип relation (regular_table, partitioned_parent, partition_leaf).

  • Ограничения pg_archive и pg_columnar.

  • Возможность прямого перемещения или необходимость пересоздания таблицы.

В связи с этим, pg_ilm реализует модель переходов в виде ограниченного автомата состояний, а не бинарной модели горячие/холодные данные.

F.49.3. Установка #

Расширение pg_ilm доступно начиная с версии Tantor SE 18.3. Перед установкой необходимо подготовить экземпляр Tantor SE, конфигурацию сервера и вспомогательные расширения.

F.49.3.1. Предварительные условия #

Перед установкой должны быть доступны:

  • pg_archive — как исполнительный слой

  • pg_columnar — для переходов в columnar storage

  • pg_cron — для планирования фоновых задач

  • pg_partman — для обслуживания секционирования

F.49.3.2. Настройка shared_preload_libraries #

Перед запуском сервера необходимо подключить фоновые библиотеки в shared_preload_libraries в postgresql.conf:

shared_preload_libraries = 'pg_archive_bgw,pg_cron,pg_partman_bgw'

Параметр shared_preload_libraries применяется только при старте сервера. После изменения postgresql.conf требуется перезапуск экземпляра. В Tantor SE параметры данного класса относятся к параметрам запуска сервера и не применяются через простой reload конфигурации.

F.49.3.3. Подготовка каталогов для tablespace #

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

Типовой пример:

mkdir -p /path/to/ilm_hot_ts
mkdir -p /path/to/ilm_cold_ts
chown postgres:postgres /path/to/ilm_hot_ts /path/to/ilm_cold_ts
chmod 700 /path/to/ilm_hot_ts /path/to/ilm_cold_ts

Имена пользователя и пути зависят от конкретной инсталляции. Каталоги должны быть доступны системному пользователю, от имени которого запущен сервер Tantor SE.

После подготовки каталогов табличные пространства создаются SQL-командами:

CREATE TABLESPACE ilm_hot_ts  LOCATION '/path/to/ilm_hot_ts';
CREATE TABLESPACE ilm_cold_ts LOCATION '/path/to/ilm_cold_ts';

F.49.3.4. Подготовка схем #

Перед созданием расширений рекомендуется заранее создать схемы, в которых будут размещены служебные объекты pg_partman и pg_archive:

CREATE SCHEMA IF NOT EXISTS partman;
CREATE SCHEMA IF NOT EXISTS archive;

Использование отдельных схем позволяет изолировать служебные объекты от пользовательских данных и упрощает сопровождение.

F.49.3.5. Порядок создания расширений #

Расширения должны создаваться в следующем порядке:

CREATE EXTENSION IF NOT EXISTS pg_cron CASCADE;
CREATE EXTENSION IF NOT EXISTS pg_partman SCHEMA partman;
CREATE EXTENSION IF NOT EXISTS pg_archive SCHEMA archive CASCADE;
CREATE EXTENSION IF NOT EXISTS pg_ilm CASCADE;

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

  1. pg_cron должен быть доступен до настройки runtime-задач.

  2. pg_partman должен быть установлен до включения логики обслуживания partitioned parent.

  3. pg_archive должен быть установлен до создания executor-path.

  4. pg_ilm устанавливается последним, так как опирается на уже доступные зависимые компоненты.

При установке pg_archive автоматически устанавливается требуемое расширение pg_columnar, если оно ещё не установлено в базе.

F.49.3.6. Проверка установки #

После создания расширений рекомендуется проверить:

  • Наличие необходимых расширений:

    SELECT extname
    FROM pg_extension
    WHERE extname IN ('pg_archive', 'pg_columnar', 'pg_cron', 'pg_ilm', 'pg_partman')
    ORDER BY extname;
    

    Результат:

       extname   
    -------------
     pg_archive
     pg_columnar
     pg_cron
     pg_ilm
     pg_partman
    
  • Наличие схем partman и archive:

    SELECT nspname
    FROM pg_namespace
    WHERE nspname IN ('archive', 'partman')
    ORDER BY nspname;
    

    Результат:

     nspname 
    ---------
     archive
     partman
    
  • Наличие требуемых tablespace, например:

    SELECT spcname, pg_tablespace_location(oid)
    FROM pg_tablespace
    WHERE spcname IN ('ilm_hot_ts', 'ilm_cold_ts')
    ORDER BY spcname;
    

    Результат:

       spcname   |                     pg_tablespace_location                      
    -------------+-----------------------------------------------------------------
     ilm_cold_ts | /path/to/ilm_cold_ts
     ilm_hot_ts  | /path/to/ilm_hot_ts
    (2 rows)
    
  • Корректность значения shared_preload_libraries:

    SELECT DISTINCT lib
    FROM pg_settings,
        unnest(string_to_array(setting, ',')) AS lib
    WHERE name = 'shared_preload_libraries'
    AND trim(lib) IN ('pg_archive_bgw', 'pg_cron', 'pg_partman_bgw')
    ORDER BY lib;
    

    Результат:

          lib       
    ----------------
     pg_archive_bgw
     pg_cron
     pg_partman_bgw
    (3 rows)
    
  • Успешный старт экземпляра после изменения конфигурации.

    SELECT pg_postmaster_start_time();
    

    Результат — успешный вывод даты и времени старта экземпляра.

F.49.3.7. Инициализация runtime #

После установки расширений и подготовки tablespace необходимо выполнить инициализацию runtime-конфигурации pg_ilm.

Типовой пример (конфигурация с вычислением рекомендаций 4 раза в сутки):

SELECT ilm.init(
  p_partman_interval             => '1 day',
  p_partman_retention            => '180 days',
  p_stats_schedule               => '0 */6 * * *',
  p_cleanup_schedule             => '0 3 * * *',
  p_partman_maintenance_schedule => '0 */6 * * *',
  p_archive_rules_schedule       => '0 */6 * * *'
);

В данном примере:

  • p_partman_interval — интервал секционирования (размер партиции) составляет 1 день.

  • p_partman_retention — история статистики хранится в течение 180 дней.

  • p_stats_schedule — сбор статистики выполняется каждые 6 часов.

  • p_cleanup_schedule — очистка служебных данных выполняется ежедневно в 03:00.

  • p_partman_maintenance_schedule — обслуживание partitioning выполняется каждые 6 часов.

  • p_archive_rules_schedule — вычисление и применение правил архивирования выполняется каждые 6 часов (4 раза в сутки).

Значения p_partman_interval и p_partman_retention не являются фиксированными требованиями. Они определяют, как будет секционироваться и сколько будет храниться служебная статистика pg_ilm.

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

Частота выполнения задач и срок хранения статистики могут быть изменены в зависимости от профиля нагрузки, объёма данных и требований к глубине исторического анализа.

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

F.49.3.8. Результат #

После завершения установки система должна быть готова к:

  • Созданию правил архивирования.

  • Сбору статистики активности.

  • Вычислению рекомендаций.

  • dry-run и выполнению переходов через pg_archive.

F.49.4. Быстрый старт #

В данном разделе приведён типовой пример начального включения pg_ilm в эксплуатационной конфигурации.

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

  • Статистика активности собирается 4 раза в сутки.

  • Рекомендации формируются на основе уже накопленных данных.

  • Данные считаются кандидатами на охлаждение после 30 дней отсутствия значимой write-активности.

  • Выполнение рекомендаций производится явно, по решению администратора.

Раздел разбит на два самостоятельных сценария:

Каждый сценарий можно использовать независимо от другого.

F.49.4.1. Сценарий для обычной таблицы #

Ниже приведён минимальный самодостаточный пример для обычной таблицы.

  1. Подготовка тестовой схемы:

    CREATE SCHEMA IF NOT EXISTS t;
    

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

  2. Создание таблицы:

    CREATE TABLE t.r1 (
        id bigint,
        ts timestamptz,
        payload text
    );
    

    Таблица создаётся в стандартном row-oriented формате (heap) и, если явно не указано иное, размещается в effective tablespace по умолчанию.

  3. Наполнение данными:

    INSERT INTO t.r1
    SELECT
        g,
        now() - (g || ' seconds')::interval,
        repeat('x', 100)
    FROM generate_series(1, 100000) g;
    

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

  4. Создание правила архивирования:

    SELECT ilm.archive_rule_upsert(
        p_target_table       => 't.r1',
        p_target_kind        => 'regular_table',
        p_target_state       => 'cold_columnar',
        p_cold_access_method => 'columnar',
        p_cold_tablespace    => 'ilm_cold_ts',
        p_cold_after         => '30 days',
        p_keep_indexes       => true
    );
    

    В данном примере правило означает следующее:

    • Объектом правила является таблица t.r1.

    • Правило применяется как к regular_table, без автоопределения типа.

    • Целевым состоянием является cold_columnar.

    • На холодном шаге требуется переход к columnar.

    • Конечное размещение должно быть выполнено в ilm_cold_ts.

    • Таблица считается кандидатом на охлаждение после 30 дней отсутствия значимой write-активности.

    • Индексы должны быть сохранены в пределах поддерживаемого backend-path.

    Пример результата выполнения:

    NOTICE:  Archive rule applied: target=t.r1, target_kind=regular_table, target_state=cold_columnar, cold_access_method=columnar, warm_tablespace=NULL, cold_tablespace=ilm_cold_ts
     archive_rule_upsert 
    ---------------------
                       1
    (1 row)
    

    Значение в результирующей строке — идентификатор созданного или обновлённого правила. Сообщение NOTICE показывает итоговую нормализованную конфигурацию правила, которая будет использована при расчёте рекомендаций.

  5. Сбор статистики:

    SELECT ilm.collect_stats_snapshot();
    

    Сбор статистики фиксирует текущее состояние активности relation, включая write-нагрузку. Это позволяет вычислять рекомендации не по предположениям, а по актуальным накопленным данным на момент расчёта.

    В production-сценарии этот шаг обычно не выполняется вручную, так как сбор статистики запускается автоматически по расписанию, заданному через ilm.init(...).

  6. Получение рекомендаций:

    SELECT
        rule_id,
        target_table,
        current_state,
        recommended_next_state,
        recommendation_status,
        prepared_call_sql
    FROM ilm.recommend_archive_actions(NULL, now(), FALSE)
    WHERE target_table = 't.r1';
    

    В запрос включены:

    • rule_id — идентификатор правила, в рамках которого построена рекомендация.

    • target_table — relation, к которому относится рекомендация.

    • current_state — определённое текущее физическое состояние.

    • recommended_next_state — следующий допустимый переход.

    • recommendation_status — статус рекомендации.

    • prepared_call_sql — подготовленный SQL-вызов для исполнения.

    Типовой результат:

     rule_id | target_table | current_state | recommended_next_state | recommendation_status | prepared_call_sql
    ---------+--------------+---------------+------------------------+-----------------------+-------------------------------------------------------------
           1 | t.r1         | warm_row      | cold_columnar          | recommend             | SELECT * FROM ilm.execute_recommendations(...)
    (1 row)
    

    Интерпретация результата:

    • recommend — для объекта найден допустимый следующий шаг.

    • skip — переход не требуется либо в текущий момент невозможен.

    • prepared_call_sql — можно использовать как готовую форму вызова для ручного выполнения.

  7. Выполнение рекомендации:

    SELECT *
    FROM ilm.execute_recommendations(
        p_target_table := 't.r1'::regclass,
        p_dry_run := FALSE
    );
    

    При выполнении pg_ilm выбирает соответствующий executor-path и вызывает низкоуровневую процедуру pg_archive. В зависимости от текущего состояния это может быть:

    • Перенос в другой tablespace.

    • Смена access method.

    • recreate-path с сохранением имени relation.

    • Комбинированный переход с сохранением структуры таблицы.

  8. Проверка результата:

    SELECT
        't.r1'::regclass AS relation_name,
        ilm._relation_access_method('t.r1'::regclass) AS access_method,
        ilm._relation_tablespace_name('t.r1'::regclass) AS tablespace_name;
    

    Ожидаемый результат:

    • access_method = columnar

    • tablespace_name = ilm_cold_ts

    Это означает, что таблица приведена к целевому cold-состоянию в терминах физического размещения и access method.

F.49.4.2. Сценарий для секционированной таблицы #

Ниже приведён полный самодостаточный пример для partitioned_parent и его leaf-партиций с использованием pg_partman.

  1. Создание partitioned parent:

    CREATE TABLE t.p1 (
        id bigint,
        ts timestamptz NOT NULL,
        payload text
    ) PARTITION BY RANGE (ts);
    

    Parent-таблица задаёт общую структуру данных и ключ секционирования. Правило pg_ilm создаётся именно на parent, а рекомендации затем вычисляются для leaf-партиций.

  2. Регистрация в pg_partman:

    SELECT partman.create_parent(
        p_parent_table => 't.p1',
        p_control      => 'ts',
        p_interval     => '1 day',
        p_premake      => 1
    );
    

    Этот шаг необходим для передачи обслуживания секционирования расширению pg_partman.

    Параметры примера означают:

    • p_parent_table — parent relation, которая будет обслуживаться.

    • p_control — колонка секционирования.

    • p_interval = '1 day' — дневной интервал для range-партиций.

    • p_premake = 1 — заранее поддерживается одна будущая секция.

    После регистрации pg_partman получает возможность автоматически создавать последующие секции и выполнять их обслуживание по расписанию.

  3. Создание leaf-партиции (если требуется вручную):

    CREATE TABLE t.p1_p20260101
    PARTITION OF t.p1
    FOR VALUES FROM ('2026-01-01') TO ('2026-02-01');
    

    Этот шаг приведён только для наглядности. В типовой эксплуатации leaf-партиции обычно создаются и обслуживаются автоматически через pg_partman.

  4. Наполнение данными:

    INSERT INTO t.p1_p20260101
    SELECT g, now() - interval '40 days', repeat('x', 100)
    FROM generate_series(1, 10000) g;
    

    В примере используются данные, которые уже достаточно «стары» для формирования рекомендации на охлаждение при пороге 30 days.

  5. Создание правила для parent:

    SELECT ilm.archive_rule_upsert(
        p_target_table       => 't.p1',
        p_target_kind        => 'partitioned_parent',
        p_target_state       => 'cold_columnar',
        p_cold_access_method => 'columnar',
        p_cold_tablespace    => 'ilm_cold_ts',
        p_cold_after         => '30 days'
    );
    

    Правило задаёт:

    • parent relation t.p1 как точку управления жизненным циклом.

    • Применение к partitioned_parent.

    • Целевое состояние leaf-партиций: cold_columnar.

    • Конечный access method: columnar.

    • Конечный tablespace: ilm_cold_ts.

    • Порог перехода: 30 дней отсутствия значимой активности.

    Пример результата выполнения:

    NOTICE:  Archive rule applied: target=t.p1, target_kind=partitioned_parent, target_state=cold_columnar, cold_access_method=columnar, warm_tablespace=NULL, cold_tablespace=ilm_cold_ts
     archive_rule_upsert 
    ---------------------
                       1
    (1 row)
    

    Как и для обычной таблицы, NOTICE показывает нормализованный итог правила, а возвращаемое значение — идентификатор записи в archive_rules.

  6. Сбор статистики:

    SELECT ilm.collect_stats_snapshot();
    

    Сбор статистики позволяет зафиксировать состояние активности parent и leaf-партиций на момент расчёта рекомендаций. Для партиционированных таблиц это особенно важно, поскольку решение принимается не для parent как контейнера, а для отдельных leaf-partitions.

  7. Получение рекомендаций:

    SELECT
        rule_id,
        target_table,
        current_state,
        recommended_next_state,
        recommendation_status,
        prepared_call_sql
    FROM ilm.recommend_archive_actions(NULL, now(), FALSE)
    WHERE target_table LIKE 't.p1%';
    

    Запрос возвращает рекомендации уже для конкретных leaf-партиций, соответствующих parent-правилу.

    Пример результата:

     rule_id |     target_table      | current_state | recommended_next_state | recommendation_status | prepared_call_sql
    ---------+------------------------+---------------+------------------------+-----------------------+-------------------------------------------------------------
           1 | t.p1_p20260101        | warm_row      | cold_columnar          | recommend             | SELECT * FROM ilm.execute_recommendations(...)
    (1 row)
    

    Это означает, что:

    • Правило rule_id = 1 применилось к leaf-партиции t.p1_p20260101.

    • Текущее состояние leaf определено как warm_row.

    • Следующий допустимый переход — cold_columnar.

    • Рекомендация является исполнимой.

    • Для неё подготовлен SQL-вызов.

  8. Выполнение рекомендации:

    SELECT * FROM ilm.execute_recommendations(
        p_target_table := 't.p1_p20260101'::regclass,
        p_dry_run := FALSE
    );
    

    В этом случае будет выполнен именно переход для leaf-партиции, а не для parent relation в целом. Низкоуровневый путь подбирается в зависимости от её текущего состояния и целевого cold-state.

  9. Проверка результата:

    SELECT
        't.p1_p20260101'::regclass AS relation_name,
        ilm._relation_access_method('t.p1_p20260101'::regclass) AS access_method,
        ilm._relation_tablespace_name('t.p1_p20260101'::regclass) AS tablespace_name;
    

    Ожидаемый результат:

    • access_method = columnar

    • tablespace_name = ilm_cold_ts

    Это подтверждает, что leaf-партиция переведена в конечное cold-состояние.

F.49.4.3. Примечание #

Оба сценария демонстрируют полный цикл работы pg_ilm:

  1. Накопление и фиксация статистики.

  2. Вычислению рекомендаций.

  3. Явное выполнение допустимого перехода.

  4. Проверка физического результата.

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

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

F.49.5. Конфигурация #

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

F.49.5.1. Модель состояний #

pg_ilm использует конечный набор физических состояний хранения данных, определяемых комбинацией двух характеристик:

  • access method (heap или columnar)

  • размещение данных (effective tablespace)

Основные состояния:

  • hot_row — row-oriented хранение (heap) в базовом или целевом (горячем) tablespace.

  • warm_row — row-oriented хранение (heap) с возможным перемещением в целевое (горячее) tablespace.

  • warm_columnar — columnar хранение в целевом (горячем) tablespace.

  • cold_columnar — columnar хранение в целевом (архивном) tablespace.

Состояние relation определяется фактическими значениями access method и tablespace, а не только конфигурацией правила.

F.49.5.2. Модель переходов #

pg_ilm не пытается сразу переводить relation в конечное состояние, а вычисляет только следующий допустимый шаг. Это связано с тем, что допустимость перехода определяется не только целевой политикой, но и текущим физическим состоянием relation.

Для текущей модели используются следующие допустимые переходы охлаждения:

  • hot_row → warm_row — перенос row-oriented relation в холодный tablespace без смены access method.

  • hot_row → warm_columnar — конвертация в columnar без финального cold-placement.

  • warm_row → cold_columnar — конвертация relation, уже размещённого в cold tablespace, в columnar.

  • warm_columnar → cold_columnar — финальный перевод columnar relation в cold tablespace.

Для regular table и partition leaf набор допустимых состояний общий, но executor-path различается. В частности, часть columnar-переходов для partition leaf реализуется через recreate-path, а не через прямое перемещение.

pg_ilm всегда возвращает только ближайший допустимый переход. Поэтому правило с целевым состоянием cold_columnar может приводить к рекомендации warm_row или warm_columnar, если именно такой шаг является корректным на данном этапе.

F.49.5.3. Способы конфигурации #

Конфигурация системы выполняется на двух уровнях:

  1. Глобальная runtime-конфигурация (ilm.init, ilm.apply_config_changes, ilm.save_config).

  2. Правила архивирования (ilm.archive_rule_upsert и связанные функции управления правилами).

F.49.5.4. Runtime-конфигурация #

Runtime-конфигурация задаёт:

  • Расписание сбора статистики.

  • Расписание очистки служебных данных.

  • Расписание обслуживания pg_partman.

  • Расписание фонового пересчёта рекомендаций.

  • Интервалы секционирования и хранения ilm.stats_history.

F.49.5.4.1. ilm.init(...) #

Функция ilm.init(...) является основной точкой начальной инициализации. Она сохраняет конфигурацию, настраивает pg_partman для ilm.stats_history и переопределяет фоновые задания pg_cron.

Параметры:

  • p_partman_interval — интервал секционирования ilm.stats_history.

  • p_partman_retention — срок хранения статистики.

  • p_stats_schedule — cron-расписание сбора статистики.

  • p_cleanup_schedule — cron-расписание очистки.

  • p_partman_maintenance_schedule — cron-расписание обслуживания pg_partman.

  • p_archive_rules_schedule — cron-расписание фонового запуска ilm.run_archive_rules().

Пример:

SELECT ilm.init(
  p_partman_interval             => '1 day',
  p_partman_retention            => '180 days',
  p_stats_schedule               => '0 */6 * * *',
  p_cleanup_schedule             => '0 3 * * *',
  p_partman_maintenance_schedule => '0 */6 * * *',
  p_archive_rules_schedule       => '0 */6 * * *'
);
F.49.5.4.2. ilm.apply_config_changes(...) #

Функция ilm.apply_config_changes(...) используется для изменения уже существующей runtime-конфигурации без повторного описания логики инициализации. Она:

  1. Сохраняет новые значения в ilm.config.

  2. Переинициализирует конфигурацию pg_partman для ilm.stats_history.

  3. Переопределяет cron-задания в соответствии с новыми расписаниями.

Функция удобна при изменении расписаний в рабочей системе.

F.49.5.4.3. ilm.save_config(...) #

Функция ilm.save_config(...) обновляет значения в ilm.config, но сама по себе не пересоздаёт cron-задачи и не переинициализирует pg_partman. Она полезна как низкоуровневый API, если требуется отдельно сохранить конфигурацию без немедленного применения.

F.49.5.4.4. Ограничения runtime-конфигурации #
  • Расписания должны быть заданы в формате cron.

  • Слишком частый сбор статистики увеличивает нагрузку на систему.

  • Слишком редкий — снижает актуальность рекомендаций.

  • Срок хранения статистики должен выбираться с учётом требуемой глубины исторического анализа.

  • Параметры runtime влияют только на накопление данных и расчёт рекомендаций, но не включают автоматическое выполнение archive-переходов.

F.49.5.5. Управление правилами архивирования #

Для управления правилами используются следующие объекты API:

  • ilm.archive_rule_upsert(...) — создать или обновить правило.

  • ilm.archive_rule_delete(...) — удалить правило.

  • ilm.archive_rule_set_enabled(...) — включить или отключить правило.

  • ilm.archive_rules_list — просмотреть текущую конфигурацию правил в нормализованном виде.

F.49.5.6. Конфигурация правила (ilm.archive_rule_upsert) #

Функция ilm.archive_rule_upsert(...) создаёт новое правило или обновляет уже существующее правило для target_table.

F.49.5.6.1. Основные параметры #
  • p_target_table — целевой объект типа regclass, параметр обязателен

  • p_target_kind — тип объекта:

    • regular_table

    • partitioned_parent

    • auto — определяется динамически при расчёте рекомендаций

  • p_target_state — целевое состояние:

    • hot_row

    • warm_row

    • warm_columnar

    • cold_columnar

  • p_control_column — колонка секционирования для partitioned_parent

  • p_max_age — максимальный возраст секции, используется для parent-правил

  • p_cold_after — интервал неактивности, после которого relation может считаться кандидатом на охлаждение

  • p_min_age — минимальный возраст relation/partition для рассмотрения

  • p_idle_threshold — допустимый порог write-неактивности

  • p_min_table_size_bytes — минимальный размер relation, начиная с которого рекомендация вообще имеет смысл

  • p_pg_archive_schema — схема, в которой установлено pg_archive, по умолчанию archive

  • p_target_schema — схема назначения, если требуется изменение схемы при архивировании

  • p_warm_tablespace — tablespace для целевого горячего размещения

  • p_cold_access_method — access method для cold-path, допустимые значения логически ограничены политикой

  • p_cold_tablespace — tablespace конечного холодного размещения

  • p_keep_indexes — сохранять ли индексы при recreate-path

  • p_keep_publication — сохранять ли участие relation в публикациях

  • p_enabled — включено ли правило

F.49.5.6.2. Полный пример #
SELECT ilm.archive_rule_upsert(
    p_target_table           => 't.r1',
    p_target_kind            => 'regular_table',
    p_target_state           => 'cold_columnar',
    p_control_column         => NULL,
    p_max_age                => NULL,
    p_cold_after             => '30 days',
    p_min_age                => '0 days',
    p_idle_threshold         => '30 days',
    p_min_table_size_bytes   => 0,
    p_pg_archive_schema      => 'archive',
    p_target_schema          => NULL,
    p_warm_tablespace        => 'ilm_hot_ts',
    p_cold_access_method     => 'columnar',
    p_cold_tablespace        => 'ilm_cold_ts',
    p_keep_indexes           => true,
    p_keep_publication       => false,
    p_enabled                => true
);
F.49.5.6.3. Встроенные ограничения archive_rule_upsert #

Функция валидирует часть комбинаций параметров ещё на этапе создания правила.

В частности:

  • Состояния warm_columnar и cold_columnar требуют p_cold_access_method = 'columnar'.

  • При p_target_kind = 'auto' тип relation будет определён во время расчёта рекомендаций.

  • Если для warm_row или cold_columnar не задан p_cold_tablespace, будет выдано NOTICE, что cooling-transition сохранит relation в текущем tablespace.

  • Если для warm_columnar не задан p_warm_tablespace, будет выдано NOTICE, что relation останется в текущем tablespace.

Таким образом, часть ошибок предотвращается уже на уровне объявления правила, а часть фиксируется как допустимое, но неидеальное поведение через NOTICE.

F.49.5.7. Просмотр правил (ilm.archive_rules_list) #

Представление ilm.archive_rules_list возвращает список правил в удобном для чтения виде.

Оно дополнительно показывает:

  • resolved_target_kind — фактически разрешённый тип relation.

  • enabled — включено ли правило.

  • Параметры холодного и горячего размещения.

  • Временные пороги и флаги сохранения структуры.

Пример:

SELECT *
FROM ilm.archive_rules_list
ORDER BY target_table;

Это представление рекомендуется использовать как основной операторский способ просмотра текущих правил.

F.49.5.8. Включение и отключение правила (ilm.archive_rule_set_enabled) #

Функция ilm.archive_rule_set_enabled(...) изменяет только флаг enabled и обновляет updated_at.

Пример отключения:

SELECT ilm.archive_rule_set_enabled('t.r1'::regclass, false);

Пример повторного включения:

SELECT ilm.archive_rule_set_enabled('t.r1'::regclass, true);

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

F.49.5.9. Удаление правила (ilm.archive_rule_delete) #

Функция ilm.archive_rule_delete(...) удаляет правило по target_table.

Пример:

SELECT ilm.archive_rule_delete('t.r1'::regclass);

Удаление правила прекращает дальнейший расчёт рекомендаций для указанного объекта.

F.49.5.10. Ограничения конфигурации правил #

  • Для перехода в columnar требуется установленное расширение pg_columnar.

  • Правило для partitioned_parent должно задаваться на parent-таблицу, рекомендации затем строятся уже для leaf-партиций.

  • Для partitioned_parent ограничение схемы требует наличия p_control_column и p_max_age.

  • Наличие внешних ключей может блокировать recreate-path.

  • identity-колонки (GENERATED AS IDENTITY) не поддерживаются при преобразовании.

  • Не все индексы могут быть восстановлены для columnar.

  • Не всякая комбинация target_state, access method и tablespace приводит к немедленно исполнимому переходу: в этом случае pg_ilm предложит промежуточный шаг либо вернёт skip или blocked.

F.49.5.11. Поведение по умолчанию #

Если параметр явно не задан, используется значение по умолчанию, определённое в API:

  • p_target_kind = 'auto'

  • p_target_state = 'cold_columnar'

  • p_cold_after = '30 days'

  • p_min_age = '0 minutes'

  • p_idle_threshold = '30 days'

  • p_min_table_size_bytes = 0

  • p_pg_archive_schema = 'archive'

  • p_cold_access_method = 'columnar'

  • p_keep_indexes = true

  • p_keep_publication = false

  • p_enabled = true

Эти значения удобны для тестовых и демонстрационных сценариев, но в production-конфигурации обычно должны быть явно скорректированы.

Конфигурация pg_ilm должна учитывать фактические ограничения физического уровня хранения и доступные executor-path, так как именно они определяют допустимость переходов и последовательность рекомендаций.

F.49.6. Использование #

В этом разделе рассматривается использование pg_ilm после того, как runtime уже инициализирован, а правила архивирования созданы.

F.49.6.1. Flamegraph активности #

Перед анализом рекомендаций pg_ilm целесообразно оценить фактическую активность физических relation за интересующий период. Для этого расширение предоставляет набор flamegraph-функций, построенных на основе накопленной истории ilm.stats_history.

Инструмент flamegraph предназначен для:

  • Выявления наиболее горячих relation по write-активности.

  • Предварительной оценки того, какие relation не следует рассматривать как кандидаты на охлаждение.

  • Сравнения активности heap- и columnar-relation в одном отчёте.

  • Визуального анализа накопленной нагрузки за фиксированный период.

Flamegraph-отчёты строятся только по физическим relation. Parent-таблицы секционирования (relkind = 'p') из отчётов исключаются, а в вывод попадают только реальные хранимые relation, включая leaf-партиции.

F.49.6.2. Принцип работы flamegraph #

Flamegraph опирается на периодические snapshot-записи в ilm.stats_history. Для каждой relation вычисляются дельты между последовательными snapshot, после чего агрегируется активность за выбранный период.

Для визуализации используется нормализованная шкала длиной 20 символов. Чем выше накопленная write-активность relation относительно остальных relation в отчёте, тем длиннее значение в колонке flame.

Важно учитывать, что flamegraph:

  • Не является прямой рекомендацией к архивированию.

  • Не заменяет результат recommend_archive_actions(...).

  • Используется как вспомогательный операторский инструмент перед анализом рекомендаций.

F.49.6.3. Основные flamegraph-функции #

F.49.6.3.1. ilm.flame(p_interval) #

Базовая функция для построения отчёта за произвольный интервал.

SELECT schemaname, relname, access_method, flame, relation_size_bytes, total_blocks_dirtied
FROM ilm.flame('30 days'::interval)
ORDER BY flame DESC, relation_size_bytes DESC;

Функция возвращает:

  • schemaname, relname — имя relation.

  • access_method — текущий access method (heap или columnar).

  • flame — нормализованную визуальную полосу активности длиной до 20 символов.

  • relation_size_bytes — текущий физический размер relation.

  • total_blocks_dirtied — суммарное число модифицированных блоков за период.

  • dirty_ratio — относительную интенсивность изменений с учётом размера relation.

  • snapshot_count, period_start, period_end — контекст расчёта.

F.49.6.3.2. Краткие функции для типовых периодов #

Для типовых периодов доступны готовые оболочки:

  • ilm.flame_d() — за 1 день.

  • ilm.flame_m() — за 1 месяц.

  • ilm.flame_k() — за 3 месяца.

  • ilm.flame_h() — за 6 месяцев.

  • ilm.flame_y() — за 1 год.

  • ilm.flame_p(p_days) — за произвольное число дней.

Примеры:

SELECT * FROM ilm.flame_d();
SELECT * FROM ilm.flame_m();
SELECT * FROM ilm.flame_p(30);

F.49.6.4. Вспомогательные функции статистики #

Для более низкоуровневого анализа доступны также:

  • ilm.get_stats_for_period(...) — агрегированные дельты по relation за период.

  • ilm.get_table_activity(...) — расширенный отчёт с access method, размером relation и dirty ratio.

Пример:

SELECT schemaname, relname, access_method, relation_size_bytes, total_blocks_dirtied, dirty_ratio
FROM ilm.get_table_activity('30 days'::interval)
ORDER BY dirty_ratio DESC, relation_size_bytes DESC;

Этот отчёт удобен, если требуется не визуальная полоса активности, а численная интерпретация интенсивности изменений.

F.49.6.5. Практическое применение flamegraph #

Типовой операторский сценарий использования flamegraph:

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

  2. Построить flamegraph-отчёт.

  3. Исключить relation с высокой write-активностью из кандидатов на охлаждение.

  4. Перейти к расчёту рекомендаций через recommend_archive_actions(...).

SELECT schemaname, relname, access_method, flame, total_blocks_dirtied
FROM ilm.flame_p(30)
ORDER BY flame DESC, relation_size_bytes DESC;

Пример вывода:

 schemaname |        relname         | access_method |        flame         | total_blocks_dirtied
------------+------------------------+---------------+----------------------+----------------------
 sales      | orders_2026_01         | heap          | ████████████████████ |                18420
 sales      | orders_2026_02         | heap          | ████████████████     |                13280
 billing    | invoices_current       | columnar      | ████████████         |                 7420
 events     | event_log_p202601      | heap          | █████████            |                 4180
 archive    | invoices_2025_q4       | columnar      | ██████               |                 1330
 crm        | customers              | heap          | ████                 |                  420
 archive    | event_log_p202511      | columnar      | █                    |                   35
 public     | reference_countries    | heap          |                      |                    0
(8 rows)

В этом примере показаны relation с разным уровнем активности:

  • Активно используемые heap-таблицы.

  • Активно используемые и умеренно активные columnar-таблицы.

  • leaf-партиции с различной интенсивностью изменений.

  • Практически неиспользуемые и пустые relation.

Такой вывод удобен для первичной визуальной сортировки объектов перед анализом рекомендаций.

F.49.6.6. Ограничения Flamegraph #

  • Данные — отчёт зависит от качества и регулярности snapshot в ilm.stats_history.

  • Интерпретация — отражает только физическую write-активность и является относительной метрикой.

  • Область покрытия — учитываются только физические relation, без parent-таблиц.

После предварительного анализа flamegraph можно переходить к расчёту рекомендаций.

F.49.6.7. Общий рабочий процесс #

В общем случае работа включает четыре этапа:

  1. Накопление статистики.

  2. Вычислению рекомендаций.

  3. Анализ переходов.

  4. Execution.

pg_ilm не скрывает промежуточные шаги.

F.49.6.8. Типовой рабочий цикл #

  1. Проверка правил:

    SELECT *
    FROM ilm.archive_rules_list
    ORDER BY target_table;
    
  2. Обновление статистики:

    SELECT ilm.collect_stats_snapshot();
    
  3. Получение рекомендаций.

    Основной операторский запрос для анализа состояния объектов — ilm.recommend_archive_actions(...).

    Сигнатура функции:

    ilm.recommend_archive_actions(
        p_target_table REGCLASS DEFAULT NULL,
        p_now TIMESTAMPTZ DEFAULT now(),
        p_persist_history BOOLEAN DEFAULT TRUE
    )
    

    Параметры:

    • p_target_table — ограничивает расчёт рекомендаций конкретной relation. Если параметр не задан, анализируются все включённые правила.

    • p_now — момент времени, относительно которого вычисляется состояние и применяются временные пороги.

    • p_persist_history — определяет, нужно ли сохранять результат расчёта в ilm.archive_recommendation_history.

    Возвращаемые поля:

    • rule_id — идентификатор правила, по которому была построена рекомендация.

    • target_table — relation, к которой относится результат.

    • resolved_target_kind — фактически определённый тип объекта (regular_table, partition_leaf и т.д.).

    • current_state — текущее физическое состояние relation.

    • recommended_next_state — следующий допустимый переход.

    • recommendation_status — итог расчёта (recommend, skip, blocked).

    • recommendation_reason — пояснение, почему рекомендация была выдана или не выдана.

    • prepared_call_sql — подготовленный SQL-вызов для исполнения.

    • blocking_constraints — ограничения, препятствующие автоматическому выполнению.

    • query_compatibility_risk — риск совместимости запросов.

    • access_risk — риск, связанный с доступом к данным после изменения.

    • restore_risk — риск восстановления или возврата.

    Базовый пример полного расчёта:

    SELECT
        rule_id,
        target_table,
        resolved_target_kind,
        current_state,
        recommended_next_state,
        recommendation_status,
        recommendation_reason,
        prepared_call_sql,
        blocking_constraints,
        query_compatibility_risk,
        access_risk,
        restore_risk
    FROM ilm.recommend_archive_actions(NULL, now(), FALSE)
    ORDER BY target_table;
    

    Этот запрос рекомендуется использовать как основной операторский отчёт, так как он показывает не только саму рекомендацию, но и её контекст.

    Пример вывода:

     rule_id |     target_table      | resolved_target_kind | current_state | recommended_next_state | recommendation_status |               recommendation_reason                |                    prepared_call_sql                     | blocking_constraints | query_compatibility_risk | access_risk | restore_risk
    ---------+-----------------------+----------------------+---------------+------------------------+-----------------------+----------------------------------------------------+----------------------------------------------------------+----------------------+--------------------------+-------------+-------------
           7 | t.r1                  | regular_table        | warm_row      | cold_columnar          | recommend             | columnar cold placement is recommended             | SELECT * FROM ilm.execute_recommendations(...);          |                      | low                      | low         | high
          12 | t.p1_p20260101        | partition_leaf       | hot_row       | warm_row               | recommend             | cold tablespace move is recommended before columnar conversion | SELECT * FROM ilm.execute_recommendations(...); |                      | low                      | low         | medium
          13 | t.p2_p20260101        | partition_leaf       | warm_columnar | cold_columnar          | blocked               | final cold placement requires cold_tablespace to be configured |                                                          |                      | low                      | low         | medium
          14 | t.r2                  | regular_table        | hot_row       |                        | skip                  | table does not satisfy idle/size thresholds yet    |                                                          |                      | low                      | low         | low
    (4 rows)
    
    

    Типовые сценарии использования:

    Для расчёта рекомендаций только по одной таблице:

    SELECT *
    FROM ilm.recommend_archive_actions('t.r1'::regclass, now(), FALSE);
    

    Для принудительного пересчёта с записью в историю:

    SELECT *
    FROM ilm.recommend_archive_actions(NULL, now(), TRUE)
    ORDER BY target_table;
    

    Для анализа только текущего состояния без сохранения истории:

    SELECT target_table, current_state, recommended_next_state, recommendation_status
    FROM ilm.recommend_archive_actions(NULL, now(), FALSE)
    ORDER BY target_table;
    

    Практически рекомендуется использовать следующий подход:

    1. Сначала выполнить запрос с p_persist_history := FALSE для оперативного анализа.

    2. При необходимости повторить расчёт с p_persist_history := TRUE, если требуется зафиксировать состояние в истории.

    3. После этого переходить к выборке исполнимых рекомендаций или dry-run выполнению.

  4. Интерпретация

    • recommend — можно выполнять.

    • skip — действие не требуется.

    • blocked — есть ограничения.

F.49.6.9. Выборка исполнимых рекомендаций #

Функция ilm.list_actionable_recommendations(...) возвращает только те рекомендации, которые:

  • Имеют статус recommend.

  • Содержат подготовленный SQL-вызов (prepared_call_sql).

  • Могут быть выполнены без дополнительных ограничений.

Сигнатура функции:

ilm.list_actionable_recommendations(
    p_target_table REGCLASS DEFAULT NULL,
    p_target_kind TEXT DEFAULT NULL,
    p_target_state TEXT DEFAULT NULL
)

Параметры:

  • p_target_table — ограничивает выборку конкретной relation или leaf-партицией.

  • p_target_kind — фильтр по типу (regular_table, partition_leaf).

  • p_target_state — фильтр по целевому следующему состоянию (warm_row, warm_columnar, cold_columnar).

Возвращаемые поля:

  • target_table — relation, для которой подготовлено действие.

  • resolved_target_kind — фактический тип объекта.

  • recommended_next_state — следующий шаг жизненного цикла.

  • prepared_call_sql — готовый SQL-вызов для выполнения.

Базовый пример:

SELECT *
FROM ilm.list_actionable_recommendations();

Примеры фильтрации:

Только для конкретной таблицы:

SELECT *
FROM ilm.list_actionable_recommendations('t.r1'::regclass);

Только для leaf-партиций:

SELECT *
FROM ilm.list_actionable_recommendations(
    p_target_kind => 'partition_leaf'
);

Только переходы в cold-слой:

SELECT *
FROM ilm.list_actionable_recommendations(
    p_target_state => 'cold_columnar'
);

F.49.6.10. Dry-run #

Перед фактическим выполнением рекомендуется использовать dry-run режим:

SELECT *
FROM ilm.execute_recommendations(
    p_target_table := 't.r1'::regclass,
    p_dry_run := TRUE
);

В режиме dry-run:

  • Определяется область выполнения.

  • Отображаются кандидаты.

  • Физические изменения не выполняются.

F.49.6.11. Работа с историей рекомендаций #

История хранится в ilm.archive_recommendation_history и используется для анализа динамики.

F.49.6.11.1. Последние рекомендации #
SELECT *
FROM ilm.archive_recommendation_history
ORDER BY evaluated_at DESC
LIMIT 50;
F.49.6.11.2. История #

Раздел предназначен для анализа ранее рассчитанных рекомендаций и их эволюции во времени.

История хранит полный снимок результата recommend_archive_actions(...) на момент вычисления. В отличие от кратких операторских выборок, таблица ilm.archive_recommendation_history содержит все основные поля контекста:

  • recommendation_id уникальный идентификатор записи истории.

  • rule_id — правило, по которому был выполнен расчёт.

  • evaluated_at — момент вычисления.

  • target_table — relation, к которому относится рекомендация.

  • resolved_target_kind — фактический тип объекта (regular_table, partition_leaf).

  • current_state — определённое текущее состояние relation.

  • recommended_next_state — следующий допустимый переход.

  • recommendation_status — итог расчёта (recommend, skip, blocked).

  • recommendation_reason — пояснение причины.

  • prepared_call_sql — подготовленный SQL-вызов для исполнения.

  • blocking_constraints — ограничения, препятствующие выполнению.

  • query_compatibility_risk, access_risk, restore_risk — сопутствующая оценка рисков.

Ниже приведены типовые сценарии использования истории.

F.49.6.11.3. Базовый просмотр последних записей #
SELECT *
FROM ilm.archive_recommendation_history
ORDER BY evaluated_at DESC, recommendation_id DESC
LIMIT 50;

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

Пример вывода:

 recommendation_id | rule_id |         evaluated_at          |     target_table      | resolved_target_kind | current_state | recommended_next_state | recommendation_status |                     recommendation_reason                      |                                                  prepared_call_sql                                                  | blocking_constraints | query_compatibility_risk | access_risk | restore_risk
-------------------+---------+-------------------------------+-----------------------+----------------------+---------------+------------------------+-----------------------+------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------+----------------------+--------------------------+-------------+-------------
                17 |       3 | 2026-03-29 23:50:00.009702+03 | t.p3_p20260329_234000 | partition_leaf       | hot_row       | warm_row               | recommend             | row-oriented cold placement is recommended                             | SELECT * FROM ilm.execute_recommendations(p_target_table := 't.p3_p20260329_234000'::regclass, p_dry_run := FALSE); |                      | low                      | low         | low
                16 |       7 | 2026-03-29 23:49:00.008033+03 | t.r2                  | regular_table        | warm_row      |                        | skip                  | table already appears to be in target state warm_row                   |                                                                                                                     |                      | low                      | low         | low
                15 |       6 | 2026-03-29 23:49:00.008033+03 | t.r1                  | regular_table        | hot_row       |                        | skip                  | table does not satisfy idle/size thresholds yet                        |                                                                                                                     |                      | low                      | low         | low
                14 |       7 | 2026-03-29 23:46:00.016892+03 | t.r2                  | regular_table        | hot_row       | warm_row               | recommend             | row-oriented cold placement is recommended                             | SELECT * FROM ilm.execute_recommendations(p_target_table := 't.r2'::regclass, p_dry_run := FALSE);                  |                      | low                      | low         | low
(4 rows)
F.49.6.11.4. История по конкретной таблице #
SELECT *
FROM ilm.archive_recommendation_history
WHERE target_table = 't.r1'
ORDER BY evaluated_at DESC, recommendation_id DESC;

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

Пример вывода:

 recommendation_id | rule_id |         evaluated_at          | target_table | resolved_target_kind | current_state | recommended_next_state | recommendation_status |                         recommendation_reason                          |                                         prepared_call_sql                                          | blocking_constraints | query_compatibility_risk | access_risk | restore_risk
-------------------+---------+-------------------------------+--------------+----------------------+---------------+------------------------+-----------------------+------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------+----------------------+--------------------------+-------------+-------------
                12 |       6 | 2026-03-29 23:43:00.018068+03 | t.r1         | regular_table        | warm_row      | cold_columnar          | recommend             | columnar cold placement is recommended; execution may recreate directly in cold tablespace | SELECT * FROM ilm.execute_recommendations(p_target_table := 't.r1'::regclass, p_dry_run := FALSE); |                      | low                      | low         | high
                 8 |       6 | 2026-03-29 23:42:00.023564+03 | t.r1         | regular_table        | hot_row       | warm_row               | recommend             | row-oriented cold placement is recommended                             | SELECT * FROM ilm.execute_recommendations(p_target_table := 't.r1'::regclass, p_dry_run := FALSE); |                      | low                      | low         | low
                 1 |       6 | 2026-03-29 23:40:00.027896+03 | t.r1         | regular_table        | hot_row       |                        | skip                  | table does not satisfy idle/size thresholds yet                        |                                                                                                    |                      | low                      | low         | low
(3 rows)
F.49.6.11.5. Анализ изменения состояний #
SELECT
    target_table,
    current_state,
    recommended_next_state,
    recommendation_status,
    recommendation_reason,
    evaluated_at
FROM ilm.archive_recommendation_history
ORDER BY target_table, evaluated_at DESC, recommendation_id DESC;

Этот запрос удобен для анализа жизненного цикла relation без перегрузки второстепенными полями.

Пример вывода:

     target_table      | current_state | recommended_next_state | recommendation_status |                     recommendation_reason                      |         evaluated_at
-----------------------+---------------+------------------------+-----------------------+------------------------------------------------------------------------+-------------------------------
 t.p1_p20260329_233000 | warm_row      | cold_columnar          | recommend             | columnar conversion of an already cold leaf is recommended             | 2026-03-29 23:43:00.018068+03
 t.p1_p20260329_233000 | hot_row       | warm_row               | recommend             | cold tablespace move is recommended before columnar conversion         | 2026-03-29 23:42:00.023564+03
 t.p4_p20260329_233000 | warm_columnar |                        | skip                  | partition t.p4_p20260329_233000 already appears to be in target state warm_columnar | 2026-03-29 23:45:00.009105+03
 t.r2                  | warm_row      |                        | skip                  | table already appears to be in target state warm_row                  | 2026-03-29 23:49:00.008033+03
(4 rows)
F.49.6.11.6. Выборка только исполнимых рекомендаций из истории #
SELECT *
FROM ilm.archive_recommendation_history
WHERE recommendation_status = 'recommend'
ORDER BY evaluated_at DESC, recommendation_id DESC;

Этот вариант используется, когда нужно определить, какие объекты в прошлых расчётах уже были готовы к выполнению.

Пример вывода:

 recommendation_id | rule_id |         evaluated_at          |     target_table      | resolved_target_kind | current_state | recommended_next_state | recommendation_status |                     recommendation_reason                      |                                                  prepared_call_sql                                                  | blocking_constraints | query_compatibility_risk | access_risk | restore_risk
-------------------+---------+-------------------------------+-----------------------+----------------------+---------------+------------------------+-----------------------+------------------------------------------------------------------------+---------------------------------------------------------------------------------------------------------------------+----------------------+--------------------------+-------------+-------------
                17 |       3 | 2026-03-29 23:50:00.009702+03 | t.p3_p20260329_234000 | partition_leaf       | hot_row       | warm_row               | recommend             | row-oriented cold placement is recommended                             | SELECT * FROM ilm.execute_recommendations(p_target_table := 't.p3_p20260329_234000'::regclass, p_dry_run := FALSE); |                      | low                      | low         | low
                14 |       7 | 2026-03-29 23:46:00.016892+03 | t.r2                  | regular_table        | hot_row       | warm_row               | recommend             | row-oriented cold placement is recommended                             | SELECT * FROM ilm.execute_recommendations(p_target_table := 't.r2'::regclass, p_dry_run := FALSE);                  |                      | low                      | low         | low
                12 |       6 | 2026-03-29 23:43:00.018068+03 | t.r1                  | regular_table        | warm_row      | cold_columnar          | recommend             | columnar cold placement is recommended; execution may recreate directly in cold tablespace | SELECT * FROM ilm.execute_recommendations(p_target_table := 't.r1'::regclass, p_dry_run := FALSE); |                      | low                      | low         | high
(3 rows)
F.49.6.11.7. Анализ блокировок #
SELECT
    target_table,
    recommendation_reason,
    blocking_constraints,
    evaluated_at
FROM ilm.archive_recommendation_history
WHERE recommendation_status = 'blocked'
ORDER BY evaluated_at DESC, recommendation_id DESC;

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

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

     target_table      |                  recommendation_reason                   |          blocking_constraints           |         evaluated_at
-----------------------+----------------------------------------------------------+-----------------------------------------+-------------------------------
 t.p4_p20260329_233000 | final cold placement requires cold_tablespace to be configured | cold_tablespace is not configured | 2026-03-29 23:45:00.009105+03
(1 row)

История рекомендуется использовать в следующих сценариях:

  • Аудит изменения состояния relation.

  • Анализ того, когда объект перешёл из skip в recommend.

  • Диагностика причин блокировок.

  • Сопоставление выполненных действий с рекомендациями, которые предшествовали выполнению.

F.49.7. Ограничения #

Ограничения относятся к архитектуре текущей версии расширения и особенностям используемых backend-компонентов.

F.49.7.1. Данные и модель хранения #

  • Переходы между состояниями выполняются поэтапно и не гарантируют прямого перехода в целевое состояние.

  • Часть переходов требует промежуточных шагов (например, hot_row → warm_row → cold_columnar).

  • Корректность рекомендаций зависит от полноты накопленной статистики.

  • При недостаточном объёме данных (stats_history) рекомендации могут носить предварительный характер.

F.49.7.2. Ограничения выполнения #

  • Выполнение переходов не является полностью автоматическим и требует явного вызова ilm.execute_recommendations(...).

  • Часть переходов может быть заблокирована ограничениями pg_archive (например, внешние ключи, identity-колонки).

  • Переходы, требующие изменения access method (heap → columnar), могут потребовать recreate-операций.

  • При отсутствии cold_tablespace некоторые целевые состояния недостижимы.

F.49.7.3. Область покрытия #

  • Рекомендации формируются только для regular_table и leaf-партиций.

  • parent-таблицы используются только как точка задания политики.

  • Логика не учитывает бизнес-семантику данных, только физическую активность и размер.

  • flamegraph и статистика отражают только write-активность.

F.49.8. Совместимость #

Расширение pg_ilm работает в составе Tantor SE и использует ряд зависимостей.

F.49.8.1. Поддерживаемые версии #

  • Tantor SE 18.3 и выше.

  • Tantor SE совместимые механизмы статистики (pg_stat_*).

F.49.8.2. Зависимости #

Для корректной работы требуется наличие расширений:

  • pg_cron — планирование фоновых задач.

  • pg_partman — управление партиционированием ilm.stats_history.

  • pg_archive — выполнение операций перемещения и изменения формата хранения.

Отсутствие pg_archive не блокирует вычисление рекомендаций, но делает невозможным выполнение переходов.

F.49.8.3. Ограничения совместимости #

  • Поведение зависит от реализации access method (heap/columnar).

  • Поддержка columnar-формата определяется возможностями установленного backend.

  • Различия в статистических функциях (pg_stat_get_blocks_*) учитываются динамически, но могут влиять на точность расчётов.

  • При обновлении версии Tantor SE рекомендуется повторная проверка конфигурации и расписаний.

F.49.9. Примечания #

F.49.9.1. Общие замечания #

  • pg_ilm реализует модель «recommendation-first»: система предлагает действия, но не выполняет их автоматически

  • Администратор контролирует переходы и может выполнять их выборочно.

  • Подготовленные SQL-вызовы (prepared_call_sql) следует рассматривать как рекомендуемый, но не единственный способ выполнения.

F.49.9.2. Эксплуатация #

  • Рекомендуется использовать dry-run перед выполнением изменений.

  • Выполнение переходов следует планировать с учётом нагрузки на систему.

  • Рекомендуется периодически проверять актуальность правил (archive_rules_list).

F.49.9.3. Эволюция функциональности #

  • В текущей версии автоматическое выполнение не включено по умолчанию.

  • Дальнейшее развитие предполагает появление настраиваемого полностью автоматического режима.

  • Модель состояний и переходов может быть расширена в следующих версиях.

F.49.9.4. Практические рекомендации #

  • Использовать flamegraph как предварительный фильтр перед анализом рекомендаций.

  • Не выполнять переходы для активно используемых relation.

  • Учитывать риски (query_compatibility_risk, restore_risk) при принятии решений.

  • Анализировать историю (archive_recommendation_history) при диагностике поведения системы.