F.46. pgpro_autopart — динамическое создание секций #
Расширение pgpro_autopart позволяет создавать секции динамически, то есть производит автоматическое секционирование при добавлении или изменении данных в таблице. Самый быстрый способ создания секций — вручную или по расписанию с помощью планировщика. Однако для некоторых задач скорость добавления данных не имеет большого значения. Для таких задач pgpro_autopart реализует автоматическое секционирование с помощью триггеров для представления секционированной таблицы.
F.46.1. Установка #
Расширение pgpro_autopart входит в состав Postgres Pro. Чтобы его задействовать, создайте расширение следующим запросом:
CREATE EXTENSION pgpro_autopart;
F.46.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 ищет секцию для этой записи. Если секция не найдена, она создаётся, после чего запись изменяется в секционированной таблице.
Примечание
Оператор INSERT или UPDATE должен содержать значение ключа секционирования.
При использовании последовательности в качестве значения ключа необходимо явно задать это значение с помощью функции nextval(), поскольку опустить его нельзя. В противном случае операция INSERT или UPDATE завершится ошибкой.
В настоящее время поддерживаются только таблицы с секционированием по диапазону значения ключа (BY RANGE), которым должен быть один столбец типа date, timestamp, timestamptz, smallint, int или bigint.
При создании секций для ключа секционирования типа date/timestamp допустимыми значениями интервала являются year, quarter, month и day. То есть новая секция создаётся для каждого нового года, квартала, месяца или дня.
Имена новых секций следуют строго определённому формату: к имени секционированной таблицы добавляется суффикс, указывающий интервал, для которого создаётся секция. Например:
dayreal_t_day_2024_05_13для таблицыreal_t_daymonthreal_t_month_2024_05для таблицыreal_t_monthquarterreal_t_quarter_2024_2для таблицыreal_t_quarteryearreal_t_year_2025для таблицыreal_t_yearintreal_t_int_120_130для таблицыreal_t_intbigint"real_t_bigint_-60_-50"для таблицыreal_t_bigint
Триггеры INSTEAD OF INSERT/UPDATE проверяют наличие секции для каждой вставляемой или изменяемой записи, что может несколько замедлить работу.
Поскольку исходная секционированная таблица переименовывается, для продолжения работы непосредственно с этой таблицей следует добавлять префикс real_.
Важно
Помните, что максимальная длина имени таблицы в Postgres Pro — 63 байта. Когда расширение pgpro_autopart создаёт секцию, оно автоматически добавляет до 29 байт (префикс real_, два подчёркивания, символы границ) к имени таблицы для типа int и до 51 байта для ключа секционирования типа bigint. Ответственность за выбор соответствующих имён таблиц, чтобы избежать ошибок, лежит на пользователе.
F.46.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.46.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.46.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
F.46. pgpro_autopart — dynamic partition creation #
The pgpro_autopart extension enables dynamic creation of partitions, that is automatic partitioning when data is added or modified in a table. The fastest way to create partitions is to do it manually or on schedule using a scheduler. However, for some tasks the speed of adding data does not matter much. For such tasks, pgpro_autopart implements automatic partitioning using triggers on a view of a partitioned table.
F.46.1. Installation #
The pgpro_autopart extension is included in Postgres Pro. To enable pgpro_autopart, create the extension using the following query:
CREATE EXTENSION pgpro_autopart;
F.46.2. Usage #
The pgpro_autopart extension uses the ap_enable_automatic_partition_creation function for automatic partitioning.
Note
Note that the extension works only with newly created tables. It cannot be used with existing partitioned tables, since it cannot track partitions previously created by users.
First, this function adds the real_ prefix to the specified table name. Then, it creates a view with the original table name and adds the INSTEAD OF INSERT/UPDATE triggers to it.
Note
Note that the database administrator should grant privileges on the view created by the ap_enable_automatic_partition_creation function manually. It is expected that these privileges are the same as on the parent table.
These triggers work as follows:
INSTEAD OF INSERT: When an entry is inserted into the view, pgpro_autopart searches for a partition for this entry. If the partition is not found, it is created. Then this entry is inserted into the partitioned table.INSTEAD OF UPDATE: When an entry is updated in the view, pgpro_autopart searches for a partition for this entry. If the partition is not found, it is created. Then this entry is updated in the partitioned table.
Note
The INSERT or UPDATE statement must contain a value for a partitioning key.
When using a sequence as the key value, it is required to explicitly set the value using nextval() because it can not be omitted. Otherwise, the INSERT or UPDATE operation will fail.
Currently, only tables with partitioning by range (BY RANGE) are supported, having one column of the date, timestamp, timestampz, smallint, int, or bigint type as a key.
When creating partitions for a partitioning key of date/timestamp types, valid values of the interval are year, quarter, month, and day. That is, a new partition is created for each new year, quarter, month or day.
Names for new partitions follow a strict format: a partitioned table name is followed by a suffix indicating the interval for which the partition is created. For example, for the following interval types table names will be as follows:
dayreal_t_day_2024_05_13for thereal_t_daytablemonthreal_t_month_2024_05for thereal_t_monthtablequarterreal_t_quarter_2024_2for thereal_t_quartertableyearreal_t_year_2025for thereal_t_yeartableintreal_t_int_120_130for thereal_t_inttablebigint"real_t_bigint_-60_-50"for thereal_t_biginttable
The INSTEAD OF INSERT/UPDATE triggers check the presence of a partition for each inserted or updated entry, and it can slow down the performance.
Since the original partitioned table is renamed, you should use its name with the real_ prefix to work directly with the table.
Important
Remember that the maximum length for the table name in Postgres Pro is 63 bytes. When pgpro_autopart creates a partition, it automatically adds up to 29 bytes (prefix real_, two underscores, symbols of borders) to the table name for the int type and up to 51 bytes for the bigint type of the partition key. It is the user's responsibility to choose appropriate table names to avoid errors.
F.46.3. ap_tables_view View #
Tables with enabled automatic partitioning are shown in the ap_tables_view view. Here is an example of the data in the 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.46.4. Functions #
-
ap_enable_automatic_partition_creation(a_relname text[, a_relschema text], a_interval text) returns void# This function is used for tables with a partitioning key of the
date,timestamp, ortimestampztype. It renames the partitioned tablea_relname(of thea_relschemaschema) by adding thereal_prefix. The function then creates a view with the same name as the original table and adds theINSTEAD OF INSERT/UPDATEtriggers to it. These triggers create a new partition when needed. The limits of the partition are determined by the defineda_interval(year, quarter, month, day).-
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# These functions are used for tables with a partitioning key of the
smallint,int, orbiginttype. They rename the partitioned tablea_relname(of thea_relschemaschema) by adding thereal_prefix. The function then creates a view with the same name as the original table and theINSTEAD OF INSERT/UPDATEtriggers for it. These triggers create a new partition when needed. The limits of the partition are determined by the originala_firstvalvalue, from which the intervals are counted, and thea_intervalvalue defining the interval length.-
ap_disable_automatic_partition_creation(a_relname text[, a_relschema text]) returns void# The function removes the triggers created by the
ap_enable_automatic_partition_creationfunction for the view of the defined partitioned tablea_relname(of thea_relschemaschema). It also deletes the view and renames the partitioned table, removing thereal_prefix from its name.
F.46.5. Example #
This example illustrates the usage of pgpro_autopart with the partitioning key of the bigint type.
Create the extension.
CREATE EXTENSION pgpro_autopart;
Create the table partitioned BY RANGE with one-column key of the bigint type.
CREATE TABLE t_bigint (b bigint, i int) PARTITION BY RANGE (b);
Use the extension to rename the t_bigint table into real_t_bigint, create the t_bigint view for this table, and then create the INSTEAD OF INSERT/UPDATE triggers. Note that the initial value for creating partitions is 100, and partitions are created at intervals of 10 in both directions.
SELECT ap_enable_automatic_partition_creation('t_bigint', 10, 100);
ap_enable_automatic_partition_creation
----------------------------------------
(1 row)
Insert two entries into the table. The real_t_bigint_110_120 partition will be created automatically after the first entry.
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
Change the key field for one of the entries. This will automatically create the real_t_bigint_-60_-50 partition.
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
Check partitions of the real_t_bigint table. There should be two of them.
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)
Check the data in the real_t_bigint table and its partitions. The table should contain two entries:
SELECT * FROM real_t_bigint; b | i -----+--- -55 | 2 111 | 1 (2 rows)
There should be one entry in the real_t_bigint_110_120 partition:
SELECT * FROM real_t_bigint_110_120; b | i -----+--- 111 | 1 (1 row)
And also there should be one entry in the real_t_bigint_-60_-50 partition.
SELECT * FROM "real_t_bigint_-60_-50"; b | i -----+--- -55 | 2 (1 row)
Disable triggers, drop the view, and rename the real_t_bigint table into t_bigint.
SELECT ap_disable_automatic_partition_creation('t_bigint');
ap_disable_automatic_partition_creation
-----------------------------------------
(1 row)
Drop the table and the extension.
DROP TABLE t_bigint; DROP TABLE DROP EXTENSION pgpro_autopart; DROP EXTENSION