Хранение всего объёма данных в одном месте удобно, но часто нерационально из-за стоимости хранения, ограничений масштабирования баз данных, усложнения администрирования и других издержек. Поэтому лучшей практикой при работе с большими объёмами данных является управление жизненным циклом информации (Information Lifecycle Management, ILM) с применением соответствующих методологий и инструментов для автоматизации процесса.

В Postgres Pro Enterprise 17 появилась возможность использовать ILM благодаря расширению pgpro_ilm, которое позволяет переносить редко используемые данные в более дешёвое хранилище по аналогии с функцией ILM в Oracle.
Проблема больших баз данных и их решение
Данные — один из важных активов любой компании. Но по мере роста компании объем генерируемых данных непрерывно увеличивается.
Если на начальных этапах для хранения информации достаточно небольшой базы данных, которую легко использовать и администрировать, то по мере разрастания БД, компании, как правило, сталкиваются с типовыми проблемами:
стоимость хранения обратно пропорциональна времени доступа к данным;
быстрых накопителей мало, и они дорогие;
актуальность данных и активность работы с ними со временем снижается;
активные операции над данными зачастую производятся только в течение относительно короткого времени (недель или месяцев) жизни данных;
со временем самый большой объем начинают занимать исторические данные, которые может быть нерационально хранить на быстрых накопителях.

Вариант с единым хранилищем для всех данных, как часто используемых, так и исторических, не самый рациональный. Поэтому бизнес вынужден искать компромисс между скоростью доступа и объёмом данных, а также способы минимизировать существующие издержки. Но когда данных и таблиц становится очень много (сотни и тысячи таблиц и секций), то хотелось бы иметь какой-то инструмент, некую большую кнопку, которая позволила бы автоматизировать этот процесс в соответствии с политиками и регламентами, применяемыми в компании.
Примечание: Чтобы понять всю суть описанных проблем, можно рассмотреть простой бытовой пример. Допустим, у вас есть гардеробная, куда вы складываете все свои вещи. В ней есть удобные полки, которые легко доступны, но их мало. Постепенно количество вещей увеличивается и рано или поздно придётся увеличивать гардеробную, поскольку количество старых и малоиспользуемых вещей со временем растет. Чтобы этого избежать, часть старых вещей надо вынести, например, в гараж или отвезти на дачу. Так они будут всё равно доступны, но не будут неоправданно занимать ограниченное место.
Что такое Information Lifecycle Management
Information Lifecycle Management — концепция управления информацией, основанная на разделении данных по критерию их ценности для бизнеса и автоматизации управлении ими с учетом политик и регламентов принятых в организации. Она помогает понять, какие данные нужны в оперативном доступе, какие могут понадобиться, но их допустимо вынести на медленные носители, а от хранения каких в оперативной базе данных можно отказаться, чтобы освободить место для новой, актуальной информации.
Примечание: Например, интернет-магазин ежедневно обрабатывает большие объёмы данных о заказах клиентов: текущие заказы и недавние покупки крайне ценны для оперативной деятельности и требуют быстрого доступа, поэтому хранятся на высокопроизводительных носителях; в то же время исторические данные о заказах, сделанных несколько лет назад, уже не столь актуальны для ежедневных операций и, хотя могут понадобиться для аналитики или отчётности, нет необходимости держать их там же где и оперативные данные — с помощью ILM эти данные можно перенести на более медленные и экономичные носители, освобождая ресурсы для актуальной информации и снижая затраты на хранение; данные, утратившие ценность и допустимые к удалению по политике компании и законодательству, могут быть архивированы или удалены, что позволяет эффективно управлять информацией на протяжении всего её жизненного цикла и поддерживать высокую производительность систем.
ILM подразумевает разделение данных на четыре основные группы:
Active. Это данные, которые часто меняются (OLTP) и для них характерны случайные чтения. Например, это может быть таблица финансовых транзакций текущего месяца.
Less Active. Данные, которые меняются редко (OLTP, OLAP), а их чтения преимущественно сканирующие по колонкам. Пример таких данных — история финансовых транзакций текущего квартала или года.
Historical. Данные, которые не меняются (OLAP). Редко выполняются сканирующие чтения по колонкам. К таким данным можно отнести, например, историческую информацию о финансовых транзакциях за предыдущие годы.
Archive. Архивные данные, которые хранят, как правило, только для соблюдения требований регуляторов.
Исходя из ценности данных и их востребованности, для каждой категории рационально выбирать свой тип носителя. Например:
активных данных зачастую относительно мало. Их можно расположить на дорогих, но быстрых NVMe-носителях;
менее востребованные данные рационально переносить на более дешевые носители — например, на классические SSD;
исторические данные оптимально переносить на HDD и/или хранить в сжатом виде;
для архивных данных достаточно простых и дешевых отчуждаемых носителей.

Примечание: В pgpro_ilm в настоящее время нет возможности вынести данные на отчуждаемые носители, такие как ленты.
Хватит лирики и теории, перейдем к деталям нашей реализации управления жизненным циклом информации. В pgpro_ilm участвует три сущности:
объект (таблица или секция), над которым совершают действие;
условие, от которого зависит выполняемое действие — например, «данные долго не менялись» или «данные давно никто не читал»;
действие — например, данные можно перенести на другой носитель или сжать.

С помощью них можно настроить правила в зависимости от потребностей и стратегии ILM в организации, например так:

Сначала, менее активные данные переносятся в табличное пространство, расположенное на более дешевых дисках, а после того, как данные переходят в категорию исторических, они переносятся в табличное пространство, расположенное на дешевых дисках большой емкости.
Примечание: Правила обрабатываются в порядке убывания периода. Это сделано специально, потому что логично сначала обработать самое «старое» правило: если оно сработало, то все остальные правила уже нет смысла обрабатывать.
Обработка условий
Для корректного использования ILM нужна статистика обращения к данным — без этого нельзя понять, какие данные «свежие», а какие «старые». Но такой статистики в Postgres Pro не было. Соответственно, мы начали искать варианты реализации сбора требуемой статистики. При этом нам было важно, чтобы решение соответствовало требованиям:
статистика не должна учитывать системных пользователей (postgres) и системные процессы (vacuum);
для отдельных пользователей должна быть возможность дополнительно задавать исключения. Это важно на случай, если при формировании статистики нужно игнорировать действия с данными отдельных специалистов;
статистика должна быть долговременной. В случае перезагрузки сервера она не должна теряться. Соответственно, ее надо хранить не только в памяти, но и на диске.
Одновременно с поиском решения для сбора статистики обращений к таблице (DML-операции), мы занималась задачами по поиску неиспользуемых привилегий в рамках расширения pgpro_usage. В итоге мы объединили усилия, чтобы реализовать сбор всей необходимой статистики в рамках расширения pgpro_usage. Теперь статистика собирается вместе, но разделена — сброс статистики для поиска неиспользуемых привилегий по умолчанию не сбрасывает статистику, используемую для ILM.
Примечание: Чтобы понять принцип раздельного хранения статистики, достаточно вспомнить одометр автомобиля. Он может отображать как пробег авто за определенный период (путевой), так и общий пробег. Причем, если сбросить путевой пробег, данные об общем пробеге останутся незатронутыми.
Статистику времени последнего доступа к таблицам pgpro_ilm получает в разрезе пользователей из функций и представлений pgpro_usage. Из всего доступного массива информации для задач ILM нужны только отдельные сведения, в зависимости от выбранного правила:
для правила NO_MODIFICATION учитываем UPDATE, INSERT, DELETE или TRUNCATE;
для правила NO_ACCESS — не только UPDATE, INSERT, DELETE, TRUNCATE, но и чтение с помощью команды SELECT.

На основе этой статистики можно понять, когда, кто и как обращался к конкретным объектам в базе данных.
От теории к практике
Теперь, когда понятен сам механизм работы нашей реализации ILM, перейдем к тому, как именно работать с расширением pgpro_ilm для Postgres Pro Enterprise 17.
Установка
Для корректной работы pgpro_ilm должно быть установлено расширение pgpro_usage. Поэтому, прежде всего, добавляем расширение pgpro_usage в переменную shared_preload_libraries в файле postgresql.conf и перезапускаем сервер базы данных.
Далее создаем расширение pgpro_usage:
CREATE EXTENSION pgpro_usage
Следом — создаем расширение pgpro_ilm.
CREATE EXTENSION pgpro_ilm
На этом подключение ilm будет завершено.
Управление списком пользователей
Используя SQL-интерфейс в pgpro_ilm, можно определить пользователей, действия которых будут игнорироваться для задач ILM. Как правило, такие исключения нужны, чтобы на статистику не оказывали влияния обращения к данным со стороны:
служебных пользователей информационной системы;
внутренних и внешних аудиторов, которым информация нужна разово;
пользователей, формирующих редкие, разовые отчеты, например выписку по счёту за определенный месяц 2020 года для контролирующих органов (если исторические данные запросили один раз в году, это не значит, что они до сих пор находятся в категории Less Active);
пользователей, выполняющих пакетные операции со старыми данными.
Для управления исключениями в pgpro_ilm предусмотрено несколько функций.
SELECT user_name, exclude_access, exclude_modification FROM pgpro_ilm.get_exclude_users(); — возвращает список исключаемых пользователей;
SELECT pgpro_ilm.set_exclude_users(array['exclude_access_user'], array['exclude_write_user']); — задает список пользователей, действия которых игнорируются при проверке правил NO_ACCESS и правил NO_MODIFICATION.
Управление правилами
Для управления правилами в pgpro_ilm предусмотрено три группы функций.
Функция для добавления нового правила
add_rule(iv_object_name text, iv_rule_type text, iv_period interval, iv_action text, iv_parameter text) returns void.
Здесь:
iv_object_name — имя объекта;
iv_rule_type — тип правила (NO_ACCESS или NO_MODIFICATION);
iv_period — период, после которого правило должно сработать;
iv_action — действие, которое надо сделать (например, перенести данные);
iv_parameter — параметр действия (например, куда надо перенести данные).
Например:
SELECT pgpro_ilm.add_rule('sales_table_section_q1_2021', 'NO_ACCESS', interval '12 mons', 'ALTER_TS', 'low_cost_sales_tablespace');
Для корректного управления правилами и перемещением данных важно предварительно выработать единый регламент, который определит, когда переносить данные и куда.
Например:
данные, которые не модифицируются более 3 месяцев, переносят на SSD;
данные не запрашивали более 6 месяцев — на HDD;
данные не читали более 12 месяцев — хранятся в сжатом виде.

Функция для удаления правил
remove_rule(iv_object_name text, iv_rule_type text, iv_period interval, iv_action text) returns void
Здесь:
iv_object_name — имя объекта;
iv_rule_type — тип правила (NO_ACCESS или NO_MODIFICATION);
iv_period — период, после которого правило должно сработать;
iv_action — действие, которое надо сделать.
Функция для получения текущего списка правил для таблицы или всех правил
get_rules([iv_object_name text]) returns table
iv_object_name — имя объекта.
Обработка правил
Теперь к функциям pgpro_ilm, которые запускают обработку правил.
В Postgres Pro можно вызывать функции обработки правил как в ручном режиме, так и автоматически с помощью планировщика задания. Второй вариант приоритетнее, поскольку снижает нагрузку на специалистов.
Для обработки правил в СУБД Postgres Pro предусмотрены две функции.
process_rules (iv_object_name text) returns void — выполняет правила для одной таблицы, где iv_object_name text — имя таблицы.
process_all_rules() returns void — выполняет все правила для всех таблиц.
Например запуск обработки правил для отдельной секции:
SELECT pgpro_ilm.process_rules('sales_table_section_q1_2021');
Примечание: Если таблица разделена на секции, то сначала проверяются правила для родительских секций, начиная с самого нижнего уровня иерархии. На каждом уровне правила рассматриваются в порядке, обратном периоду их действия. Как только для таблицы будет найдено подходящее правило, функции выполняют соответствующее действие и завершают обработку таблицы.
Что еще нужно знать
Теперь кратко остановимся на некоторых нюансах ILM.
Правила можно создавать как для секционированной таблицы в целом, так и для отдельной ее секции. Если вы создаете правила для секционированной таблицы, они автоматически наследуются для всех секций этой таблицы.
Правила для отдельных секций секционированных таблиц приоритетнее общих правил для таблиц. При этом правила, относящиеся к родительским таблицам, продолжают действовать.

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

Если таблица уже была перенесена, то повторно правило обрабатываться не будет.
Операция ALTER TABLE … SET TABLESPACE … захватывает блокировку AccessExclusiveLock. Соответственно повторный вызов функции process_rules, до того, как завершится предыдущая операция, безопасен.
Если ALTER TABLE завершается ошибкой, то повторный вызов process_rules повторяет операцию.
Для того, чтобы было проще понять, от какой даты отсчитываются периоды и как обрабатываются правила, ниже представлена небольшая анимация. Надеюсь она позволит лучше понять внутреннюю логику нашей реализации ILM:

Дополнительные инструменты
В отдельных сценариях работы с Postgres Pro Enterprise 17 одного расширения pgpro_ilm может оказаться недостаточно. Поэтому для работы с большими объемами данных можно также применять другие расширения и инструменты.
В частности:
SPLIT PARTITION и MERGE PARTITIONS — команды для разделения одной секции на несколько и объединения нескольких секций в одну соответственно.
Механизм CFS для сжатия таблиц и индексов внутри табличного пространства. В СУБД Postgres Pro поддерживаются разные алгоритмы и степени сжатия.
pgpro_autopart — расширение Postgres Pro для автоматического секционирования при добавлении или изменении данных в таблице.
pgpro_bfile — расширение, которое добавляет составной тип bfile для доступа ко внешнему файлу, то есть позволяет выносить неструктурированные данные за пределы СУБД.
pgpro_scheduler — расширение, с помощью которого можно планировать, контролировать и управлять выполнением заданий.
Shardman — технология для создания распределенной реляционной СУБД, предоставляющая строгие гарантии целостности данных.
Вместо выводов
Postgres Pro Enterprise 17 и расширения к нему позволяют выстроить полноценный пайплайн работы с данными в разных кейсах и сценариях. ILM, с помощью которого можно перемещать редко используемые данные в более дешевое хранилище, — один из таких механизмов.
Расширение pgpro_ilm включено в состав Postgres Pro Enterprise 17 как стандартное расширение и не требует отдельного лицензирования и сложной настройки.