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

В состав Postgres Pro Enterprise входят расширения pgpro_ilm и pgpro_usage, которые можно использовать для управления жизненным циклом данных. pgpro_usage собирает статистику обращений, на её основе pgpro_ilm проверяет правила перемещения таблиц, секций и индексов между табличными пространствами. Условия задают, как долго объект не изменяли или как долго к нему вообще не обращались. Этот механизм позволяет автоматизировать перенос редко используемых данных в более дешёвое хранилище.
Зачем данным жизненный цикл
Information Lifecycle Management, или ILM, — подход к управлению данными с учётом их востребованности, ценности для организации и требований к хранению. Для базы данных это означает, что по мере изменения нагрузки данные могут переходить между уровнями хранения с разной стоимостью и производительностью.
Рассмотрим историю заказов интернет-магазина. Пока заказ оформляют, оплачивают и доставляют, приложение регулярно читает и изменяет его данные. После завершения заказа количество изменений уменьшается, но информация по-прежнему нужна для возвратов, поддержки покупателей и текущей отчётности. Через несколько лет обращения могут стать редкими, хотя сама история всё ещё требуется бизнесу.
Для такого сценария можно принять следующую политику хранения. Это условный пример: конкретные сроки и носители выбирают под нагрузку своей системы.
Категория данных | Пример использования | Возможное размещение |
Активные | Оформление и сопровождение текущих заказов | Быстрое хранилище для оперативной нагрузки |
Менее активные | Возвраты и отчётность по завершённым заказам | Отдельное хранилище с меньшей стоимостью ёмкости |
Исторические | Анализ продаж прошлых лет, разбор отдельных обращений | Более медленное хранилище большой ёмкости |
Архивные | Хранение по внутреннему регламенту или требованиям законодательства | Архивная система, выбранная под требования к доступу и срокам хранения |
Администратор может вручную перемещать закрытые секции между табличными пространствами. При большом количестве секционированных таблиц такая работа требует регулярной проверки: какие секции ещё востребованы, какие перестали изменяться и какие пора перенести. pgpro_ilm позволяет выразить эти условия в правилах и применять их через SQL-интерфейс.
Область действия расширения ограничена перемещением объектов внутри базы данных. В текущей версии поддерживается перенос обычных таблиц, индексов и секций в другое табличное пространство. Архивирование на внешние носители, удаление данных и сжатие как самостоятельное действие в интерфейсе pgpro_ilm не предусмотрены. Эти задачи требуют других механизмов.
Как работает pgpro_ilm
Правило pgpro_ilm связывает объект, условие и действие. Например: если к секции заказов не обращались шесть месяцев, переместить её в табличное пространство slow_space. В SQL-интерфейсе задаются имя объекта, тип условия, период, действие ALTER_TS и имя целевого табличного пространства.
Расширение поддерживает два типа условий:
Тип правила | Что проверяет | Какие команды учитываются |
| Объект не изменялся в течение заданного периода |
|
| К объекту не обращались в течение заданного периода | Все перечисленные команды, а также |
Различие важно для выбора политики. Секция может годами оставаться неизменной и ежедневно участвовать в отчётах. Для неё условие NO_MODIFICATION может выполняться, а NO_ACCESS — нет. Перенос по отсутствию изменений нужно согласовывать с требованиями к скорости чтения.
Статистику времени последнего доступа pgpro_ilm получает от расширения pgpro_usage. Сведения доступны в разрезе пользователей, поэтому при проверке правил можно исключить обращения отдельных учётных записей. Документация рекомендует учитывать этот механизм для сервисных операций, в том числе резервного копирования и архивации: такие обращения могут мешать определить востребованность данных прикладной нагрузкой.
В нашем примере ежедневное резервное копирование истории заказов не должно означать, что эта история нужна приложению каждый день. Для пользователя, выполняющего копирование, можно настроить исключение. Сами исключения требуют осмысленного выбора: если под одной учётной записью работают и сервисный процесс, и приложение, исключение затронет обращения обоих.
Для правил одного уровня расширение проверяет периоды по убыванию. Если для объекта заданы условия с периодами шесть и три месяца, проверка начинается с полугодового периода. После обнаружения применимого правила расширение выполняет действие и заканчивает обработку объекта.
Добавление правила и его выполнение — отдельные операции. Функции управления сохраняют настройки, а функции обработки проверяют условия и запускают перенос. Поэтому для автоматической работы нужно организовать регулярный вызов обработки правил.
Установка
Сначала подключите pgpro_usage по документации к этому расширению. Затем создайте pgpro_ilm в нужной базе:
CREATE EXTENSION pgpro_ilm;
Расширение входит в состав Postgres Pro Enterprise как стандартное, отдельно устанавливать пакет не нужно.
Пример: секционированная таблица измерений
Предположим, исторические измерения хранятся на быстрых дисках вместе с актуальными данными. К части истории обращаются редко, поэтому нужно настроить её перенос в более дешёвое хранилище. Зададим условия переноса, исключим из проверки обращения служебных пользователей и проверим, как расширение выполняет правила.
Для этого возьмём пример из документации: таблицу measurement с полями city_id, logdate, peaktemp и unitsales, секционированную по диапазону logdate. В примере есть одна секция measurement_y2006m03 за март 2006 года и три её индекса. Табличное пространство slow_space уже подготовлено на медленных дисках.
Исключаем пользователей из проверки
SELECT pgpro_ilm.set_exclude_users( array['exclude_access_user'], array['Exclude Write User'] );
Функция принимает два массива имён. Первые пользователи не учитываются при проверке правил NO_ACCESS, вторые — при проверке NO_MODIFICATION. Каждый вызов сбрасывает старый список и создаёт новый. Результат смотрим так:
SELECT user_name, exclude_access, exclude_modification FROM pgpro_ilm.get_exclude_users();
Запрос вернёт по строке на пользователя с булевыми признаками. У exclude_access_user значение t в exclude_access, у Exclude Write User — t в exclude_modification.
Кого стоит внести в этот список:
служебных пользователей информационной системы, от имени которых работают резервное копирование и обслуживание;
аудиторов, которым данные нужны один раз;
авторов разовых отчётов. Допустим, контролирующий орган запросил выписку по счёту за 2020 год. Один такой запрос не делает данные снова активными, и в статистику он попадать не должен;
пользователей, которые запускают пакетные операции над старыми данными.
Добавляем правила
SELECT * FROM pgpro_ilm.add_rule('measurement', 'NO_ACCESS', interval '16 mons', 'ALTER_TS', 'slow_space'); SELECT * FROM pgpro_ilm.add_rule('measurement', 'NO_MODIFICATION', interval '16 mons', 'ALTER_TS', 'slow_space'); SELECT * FROM pgpro_ilm.add_rule('measurement_y2006m03', 'NO_ACCESS', interval '14 mons', 'ALTER_TS', 'slow_space'); SELECT * FROM pgpro_ilm.add_rule('measurement_y2006m03', 'NO_ACCESS', interval '12 mons', 'ALTER_TS', 'slow_space');
Аргументы функции add_rule идут в таком порядке: имя отношения, тип правила, период, действие и параметр действия. Имя можно указать полностью или без схемы. Во втором случае схема определяется по пути поиска search_path.
Первые два правила заданы для всей таблицы measurement: если за 16 месяцев к данным никто не обращался или их никто не менял, они переезжают в slow_space. Остальные два заданы для конкретной секции и срабатывают раньше, через 14 и 12 месяцев.
Проверяем список правил
SELECT * FROM pgpro_ilm.get_rules('measurement_y2006m03');
Функция get_rules без аргумента возвращает все правила, а с именем таблицы — только те, что к ней применимы. Для секции в список попадают и правила, унаследованные от родительской таблицы разного уровня. Пока у секции нет собственного правила NO_MODIFICATION, в списке три строки: два её правила NO_ACCESS (1 год 2 месяца и 1 год) и унаследованное NO_MODIFICATION на 1 год 4 месяца.
После добавления явного правила того же типа для секции картина меняется:
SELECT * FROM pgpro_ilm.add_rule('measurement_y2006m03', 'NO_MODIFICATION', interval '12 mons', 'ALTER_TS', 'slow_space');
Теперь в списке только явно заданные правила секции: два NO_ACCESS и NO_MODIFICATION на 1 год. Унаследованное от родителя правило исчезло.
Запускаем обработку
Правила сами по себе ничего не переносят. Перенос выполняют функции обработки:
SELECT pgpro_ilm.process_rules('measurement_y2006m03');
В примере из документации расширение сообщает, что нашло правило NO_ACCESS с периодом 1 год 2 месяца, и выполняет четыре команды: переносит таблицу и три её индекса в slow_space.
ALTER TABLE public.measurement_y2006m03 SET TABLESPACE slow_space; ALTER INDEX public.measurement_y2006m03_pkey SET TABLESPACE slow_space; ALTER INDEX public.measurement_y2006m03_city_id_idx SET TABLESPACE slow_space; ALTER INDEX public.measurement_y2006m03_logdate_idx SET TABLESPACE slow_space;
Индексы поехали вместе с таблицей, потому что для них не заданы собственные правила. Если правило для индекса есть, оно обрабатывается независимо от таблицы. В описании секции (\d+) после этого появляется строка Tablespace: "slow_space".
Повторный вызов ничего не перенесёт. Расширение определяет, что отношение уже лежит в нужном табличном пространстве, и сообщает об этом. Поэтому запускать обработку можно регулярно, не опасаясь дублирования работы.
Вызов для самой секционированной таблицы ничего не сделает:
SELECT pgpro_ilm.process_rules('measurement');
В секционированной таблице данных нет, они лежат в секциях. Расширение напишет, что подходящих правил не найдено.
Для обработки всех таблиц сразу есть процедура:
CALL pgpro_ilm.process_all_rules();
Она вызывает process_rules для каждого отношения в базе, у которого есть хотя бы одно правило.
Удаляем правила
SELECT pgpro_ilm.remove_rule('measurement', NULL, '16 month'::interval, 'ALTER_TS');
NULL вместо типа правила удаляет правила любого типа. С тем же смыслом NULL работает для периода и действия. В примере из документации после этого вызова get_rules('measurement') возвращает ноль строк.
В каком порядке работают правила
Для обычных таблиц правила проверяются по убыванию периода, то есть первым идёт самое «старое» правило. Для секций сначала проверяются правила на самом нижнем уровне иерархии, затем выше, а на каждом уровне — тоже по убыванию периода. Как только найдено подходящее правило, действие выполняется и обработка этого отношения завершается.
Если данные не трогали 16 месяцев, правила на 12 месяцев проверять уже незачем. Таблица перенесена, остальные условия ничего не добавят.
Как собрать регламент для своей базы
Прежде чем добавлять правила, договоритесь о единой политике. Пример для таблицы заказов, секционированной по месяцам. Предположим, созданы табличные пространства ssd_space и hdd_space на соответствующих дисках:
Условие | Тип правила | Период | Куда переносить |
Заказы не меняют, но читают |
| 3 месяца |
|
Заказы не читают и не меняют |
| 12 месяцев |
|
В виде вызовов это выглядит так:
SELECT pgpro_ilm.add_rule('orders', 'NO_MODIFICATION', interval '3 mons', 'ALTER_TS', 'ssd_space'); SELECT pgpro_ilm.add_rule('orders', 'NO_ACCESS', interval '12 mons', 'ALTER_TS', 'hdd_space');
Правила заданы для родительской таблицы orders и применяются ко всем её месячным секциям. Секция, к которой нужна особая политика, получает собственное правило. Для неё, как в примере с measurement, будут действовать только явно заданные правила того же типа.
Как автоматизировать запуск
Функции обработки можно вызывать вручную или по расписанию. Расписание удобнее, так как снижает нагрузку на специалистов. Для планирования заданий в Postgres Pro есть расширение pgpro_scheduler: достаточно поставить в него вызов pgpro_ilm.process_all_rules() с нужной периодичностью.
pgpro_ilm решает одну задачу и хорошо сочетается с другими инструментами. Секционирование поддерживают команды SPLIT PARTITION и MERGE PARTITIONS, а расширение pgpro_autopart создаёт секции автоматически. Сжатие данных в табличных пространствах обеспечивает механизм CFS. Это отдельные механизмы со своей документацией.
Текущие ограничения pgpro_ilm: единственное действие — перемещение в другое табличное пространство, а поддерживаются только обычные таблицы, индексы и секции секционированных таблиц.

