F.45. pgpro_autopart — динамическое создание секций #

Расширение pgpro_autopart позволяет создавать секции динамически, то есть производит автоматическое секционирование при добавлении или изменении данных в таблице. Самый быстрый способ создания секций — вручную или по расписанию с помощью планировщика. Однако для некоторых задач скорость добавления данных не имеет большого значения. Для таких задач pgpro_autopart реализует автоматическое секционирование с помощью триггеров для представления секционированной таблицы.

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

Расширение pgpro_autopart входит в состав Postgres Pro. Чтобы его задействовать, создайте расширение следующим запросом:

CREATE EXTENSION pgpro_autopart;

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

Расширение pgpro_autopart использует для автоматического секционирования функцию ap_enable_automatic_partition_creation.

Примечание

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

Сначала функция добавляет к имени указанной таблицы префикс real_, а затем создаёт представление с первоначальным именем таблицы и триггеры INSTEAD OF INSERT/UPDATE для этого представления.

Примечание

Обратите внимание, что администратор баз данных должен вручную предоставлять права на представление, созданное функцией ap_enable_automatic_partition_creation. Ожидается, что это будут те же права, что и для родительской таблицы.

Эти триггеры работают следующим образом:

  • INSTEAD OF INSERT: при попытке добавить запись в представление pgpro_autopart ищет секцию для этой записи. Если секция не найдена, она создаётся, после чего запись добавляется в секционированную таблицу.

  • INSTEAD OF UPDATE: при попытке изменить запись в представлении pgpro_autopart ищет секцию для этой записи. Если секция не найдена, она создаётся, после чего запись изменяется в секционированной таблице.

В настоящее время поддерживаются только таблицы с секционированием по диапазону значения ключа (BY RANGE), которым должен быть один столбец типа date, timestamp, timestamptz, smallint, int или bigint.

При создании секций для ключа секционирования типа date/timestamp допустимыми значениями интервала являются year, quarter, month и day. То есть новая секция создаётся для каждого нового года, квартала, месяца или дня.

Имена новых секций следуют строго определённому формату: к имени секционированной таблицы добавляется суффикс, указывающий интервал, для которого создаётся секция. Например:

day

real_t_day_2024_05_13 для таблицы real_t_day

month

real_t_month_2024_05 для таблицы real_t_month

quarter

real_t_quarter_2024_2 для таблицы real_t_quarter

year

real_t_year_2025 для таблицы real_t_year

int

real_t_int_120_130 для таблицы real_t_int

bigint

"real_t_bigint_-60_-50" для таблицы real_t_bigint

Триггеры INSTEAD OF INSERT/UPDATE проверяют наличие секции для каждой вставляемой или изменяемой записи, что может несколько замедлить работу.

Поскольку исходная секционированная таблица переименовывается, для продолжения работы непосредственно с этой таблицей следует добавлять префикс real_.

Важно

Помните, что максимальная длина имени таблицы в Postgres Pro — 63 байта. Когда расширение pgpro_autopart создаёт секцию, оно автоматически добавляет до 29 байт (префикс real_, два подчёркивания, символы границ) к имени таблицы для типа int и до 51 байта для ключа секционирования типа bigint. Ответственность за выбор соответствующих имён таблиц, чтобы избежать ошибок, лежит на пользователе.

F.45.3. Представление ap_tables_view #

Таблицы с включённым автоматическим секционированием показаны в представлении ap_tables_view. Ниже приведён пример данных в этом представлении.

SELECT * FROM ap_tables_view;
 apt_relname | apt_relschema |                                   apt_mode
-------------+---------------+-----------------------------------------------------------------------------
 t_month1    | user_schema   | automatic partition creation with using triggers on VIEW (C-implementation)
 t_bigint1   | user_schema   | automatic partition creation with using triggers on VIEW (C-implementation)
(2 rows)

F.45.4. Функции #

ap_enable_automatic_partition_creation(a_relname text[, a_relschema text], a_interval text) returns void #

Эта функция предназначена для таблиц с ключом секционирования типа date, timestamp или timestampz. Она переименовывает секционированную таблицу a_relname (схемы a_relschema), добавляя префикс real_, а затем создаёт представление с тем же именем, что и у исходной таблицы, и добавляет для него триггеры INSTEAD OF INSERT/UPDATE. Эти триггеры при необходимости создают новую секцию, границы которой определяются интервалом, заданным в параметре a_interval (год, квартал, месяц, день).

ap_enable_automatic_partition_creation(a_relname text[, a_relschema text], a_interval smallint, a_firstval smallint) returns void
ap_enable_automatic_partition_creation(a_relname text[, a_relschema text], a_interval int, a_firstval int) returns void
ap_enable_automatic_partition_creation(a_relname text[, a_relschema text], a_interval bigint, a_firstval bigint) returns void #

Эти функции используются для таблиц с ключом секционирования типа smallint, int или bigint. Они переименовывают секционированную таблицу a_relname (схемы a_relschema), добавляя префикс real_. Затем вызванная функция создаёт представление с тем же именем, что и у исходной таблицы, и триггеры INSTEAD OF INSERT/UPDATE для него. Эти триггеры при необходимости создают новую секцию, границы которой определяются исходным значением a_firstval, от которого отсчитываются интервалы, и значением a_interval, определяющим длину интервала.

ap_disable_automatic_partition_creation(a_relname text[, a_relschema text]) returns void #

Функция удаляет триггеры, созданные функцией ap_enable_automatic_partition_creation для представления указанной секционированной таблицы a_relname (схемы a_relschema). Она также удаляет представление и переименовывает секционированную таблицу, убирая из её имени префикс real_.

F.45.5. Пример #

В следующем примере показано использование расширения pgpro_autopart с ключом секционирования типа bigint.

Создайте расширение.

CREATE EXTENSION pgpro_autopart;

Создайте таблицу, секционированную с указанием BY RANGE с одностолбцовым ключом типа bigint.

CREATE TABLE t_bigint (b bigint, i int) PARTITION BY RANGE (b);

Используйте расширение, чтобы переименовать таблицу t_bigint в real_t_bigint, создать представление t_bigint для этой таблицы, а затем создать триггеры INSTEAD OF INSERT/UPDATE. Обратите внимание, что начальное значение для создания секций — 100, а секции создаются с интервалом 10 в обоих направлениях.

SELECT ap_enable_automatic_partition_creation('t_bigint', 10, 100);
 ap_enable_automatic_partition_creation
----------------------------------------
(1 row)

Добавьте две записи в таблицу. При добавлении первой записи будет автоматически создана секция real_t_bigint_110_120.

INSERT INTO t_bigint VALUES (111, 1);
NOTICE:  New partition "public"."real_t_bigint_110_120" created
INSERT 0 1
INSERT INTO t_bigint VALUES (114, 2);
INSERT 0 1

Измените у одной из записей поле ключа. При этом будет автоматически создана секция real_t_bigint_-60_-50.

UPDATE t_bigint  SET b = -55 WHERE b = 114 RETURNING *;
NOTICE:  New partition "public"."real_t_bigint_-60_-50" created
  b  | i
-----+---
 -55 | 2
(1 row)
UPDATE 1

Проверьте секции таблицы real_t_bigint. Их должно быть две.

SELECT
  c.oid::pg_catalog.regclass AS "name",
  pg_catalog.pg_get_expr(c.relpartbound, c.oid) AS "condition"
FROM
  pg_catalog.pg_class c,
  pg_catalog.pg_inherits i
WHERE
  c.oid = i.inhrelid AND i.inhparent = 'real_t_bigint'::regclass;
          name           |             condition
-------------------------+------------------------------------
 real_t_bigint_110_120   | FOR VALUES FROM ('110') TO ('120')
 "real_t_bigint_-60_-50"   | FOR VALUES FROM ('-60') TO ('-50')
(2 rows)

Проверьте данные в таблице real_t_bigint и её секциях. В таблице должно быть две записи:

SELECT * FROM real_t_bigint;
  b  | i
-----+---
 -55 | 2
 111 | 1
(2 rows)

В секции real_t_bigint_110_120 должна быть одна запись:

SELECT * FROM real_t_bigint_110_120;
  b  | i
-----+---
 111 | 1
(1 row)

Также должна быть одна запись в секции real_t_bigint_-60_-50.

SELECT * FROM "real_t_bigint_-60_-50";
  b  | i
-----+---
 -55 | 2
(1 row)

Отключите триггеры, удалите представление и переименуйте таблицу real_t_bigint в t_bigint.

SELECT ap_disable_automatic_partition_creation('t_bigint');
 ap_disable_automatic_partition_creation
-----------------------------------------

(1 row)

Удалите таблицу и расширение.

DROP TABLE t_bigint;
DROP TABLE
DROP EXTENSION pgpro_autopart;
DROP EXTENSION