Нативное интервальное партиционирование
Описание
Нативное интервальное партиционирование (или автопартиционирование) — это механизм, который позволяет автоматически создавать партиции (секции) для таблиц при перемещении или вставке новых данных со значениями, не подходящими под критерий данных для существующих партиций.
Автопартиционирование может быть вложенным. При вложенном автопартиционировании все создаваемые таблицы, кроме самой последней по уровню вложенности, являются партиционированными таблицами. Реальные данные в такой схеме хранятся только в самой последней таблице. Автопартиционирование создаст необходимые таблицы на всех уровнях вложенности.
При удалении или перемещении данных пустые партиции не удаляются.
Автопартиционирование работает следующим образом. При создании партиционированной таблицы (корневой таблицы) указываются параметры автопартиционирования. При вставке или изменении данных СУБД пытается найти подходящую партицию. Если подходящая партиция не найдена, то происходит поиск правила автопартиционирования для таблицы. Если правило найдено, то происходит создание новой таблицы и затем повторная попытка вставки данных. Данный процесс может повторяться рекурсивно для вложенного автопартиционирования.
Автопартиционирование не исключает возможности управлять партициями вручную. При этом все стандартные механизмы в СУБД продолжают работать. Однако нужно учитывать потенциальное пересечение интервалов партиций, если партиции, создаваемые вручную, частично пересекаются с диапазонами автоматически создаваемых партиций. Для исключения пересечения необходимо убедиться, что настройки автопартиционирования не приведут к созданию партиций, имеющих пересекающиеся диапазоны данных с существующими партициями.
Нативное интервальное партиционирование доступно для следующих стратегий партиционирования:
LIST
– партиция будет автоматически создаваться для каждого значения из списка;HASH
– партиции будут создаваться автоматически для каждого остатка (remainder) от деления значения хеш-функции на задаваемый делитель (modulus);RANGE
– партиции будут задаваться автоматически для каждого интервала, задаваемого в процессе создания таблицы при помощи нового синтаксиса.
Функциональность доступна только для редакций Enterprise и Enterprise для ERP-систем.
Синтаксис команды создания таблицы с включенным автопартиционированием
Автопартиционирование настраивается в момент создания таблицы.
При создании таблицы через CREATE TABLE
вместо стандартной конструкции PARTITION BY
можно использовать новую конструкцию AUTO PARTITION BY
:
CREATE * TABLE * auto_partition_spec [ ... ] *
Где auto_partition_spec
:
{ AUTO PARTITION BY RANGE ( key [, ... ] ) PERIOD ( period [, ... ] ) [ OFFSET ( offset [, ... ] ) ] |
AUTO PARTITION BY HASH ( key [, ... ] ) MODULUS ( modulus [, ... ] ) |
AUTO PARTITION BY LIST ( key [, ... ] ) }
Где *
— любые допустимые стандартные конструкции запроса.
Параметры:
key
— ключ партиционирования. Допустимы те же значения, что и в стандартной конструкцииPARTITION BY
;period
— значение периода партиций (разности значений междуFROM
иTO
в создаваемых партициях);offset
— значение смещения периода партиций. По умолчанию равен0
(для числовых интервалов) либо эпохе (для дат);modulus
— значение модуля (MODULUS
) создаваемых партиций.
Параметры должны быть указаны в соответствии с количеством и типом данных, приведенных в ключе партиционирования key
.
Возможен многократный последовательный вызов AUTO PARTITION
. Это задействует вложенное партиционирование в указанном порядке. Первым следует описание автопартиционирования для таблицы верхнего уровня, последним — для таблицы нижнего уровня.
Возможность изменить схему автопартиционирования для ранее созданной партиционированной или автопартиционированной таблицы недоступна из-за потенциально неразрешимых ситуаций при пересекающихся интервалах.
Примеры задания команд для различных правил автопартиционирования приведены в подразделе «Примеры задания команд для различных правил автопартиционирования» текущего раздела.
Настройка
Правила автопартиционирования
Под параметрами партиционирования понимаются параметры, задающие правила определения принадлежности записи к существующей или вновь создаваемой партиции.
Правила автопартиционирования для стратегии RANGE
Для интервальных (RANGE
) партиций указываются следующие параметры:
PERIOD
— период партиционирования, определяющий размер диапазона значений, которые будет содержать каждая партиция. Это значение будет соответствовать разности между параметрамиTO
иFROM
для автоматически создаваемой партиции;OFFSET
— смещение значенийTO
иFROM
относительно условного нуля.
Например, при создании таблицы с параметрами PERIOD (10) OFFSET (3)
, партиции будут создаваться для диапазонов значений «... (-7 3) (3 13) (13 23) ...»
.
Если не указывать смещение, то партиции будут создаваться со смещением:
- для числовых значений — со смещением
0
; - для значений даты или времени — со смещением от эпохи (
2000-01-01 00:00:00
).
Формулы, по которым вычисляется диапазон партиции для значения value
:
FROM = value - ( (value - OFFSET) % PERIOD )
TO = FROM + PERIOD
где %
— оператор вычисления остатка от деления левого операнда на правый. Для дат и времени под делением понимается количество интервалов времени, прошедших с момента эпохи (для дат и меток времени) или начала дня (для времен).
Для данной стратегии доступны следующие типы данных:
INTEGER
(все варианты);NUMERIC
(все варианты);DATE
;TIMESTAMP
;TIMESTAMPTZ
(используется часовой пояс, установленный на сервере);- любые другие типы, для которых определены операторы, позволяющие вычислить значение формул расчета диапазона.
Работа с типами данных с плавающей точкой (REAL
,FLOAT4
,FLOAT8
) не поддерживается из-за неоднозначности при округлении диапазонов интервалов. Выводится ошибка, например ERROR: cannot find operator %(real, real)
.
Правила автопартиционирования для стратегии HASH
Для хеш (HASH
) партиций должен быть указан модуль (MODULUS
).
Модуль определяет количество возможных партиций. При вставке или изменении данных рассчитывается хеш-значение для данных. Далее производится вычисление остатка от деления от этого значения по указанному модулю. Этот остаток (REMAINDER
) определяет партицию, в которую попадут данные.
При включенном автопартиционировании в случае необходимости будут создаваться партиции с указанным MODULUS
и рассчитанным REMAINDER
для новых данных.
Правила автопартиционирования для стратегии LIST
Для перечисляемых (LIST
) партиций параметры отсутствуют.
При поступлении данных со значением ключа партиционирования, не попадающими ни в одну созданную партицию, будет создана новая партиция для этого значения.
Именование партиций
Новые партиции создаются с именем, состоящим из:
- имени вышестоящей по уровню вложенности таблицы;
- символов
«_p»
; - числа — условного номера партиции, в типичной ситуации равному порядковому номеру в порядке создания партиций, начиная с нуля.
Блокировки при автопартиционировании
Возможна ручная установка эксклюзивной блокировки при помощи SQL-запроса LOCK TABLE
в начале транзакции, перед вставкой или изменением данных, для того, чтобы момент взаимоблокировки был обнаружен и потенциально разрешен до начала операции создания партиции.
В версиях Pangolin до 6.5.0 перед добавлением партиции выполнялась блокировка AccessExclusiveLock
на партиционированную таблицу, которая препятствовала дальнейшему прогрессу других сессий.
Выполнялась именно блокировка AccessExclusiveLock
по аналогии с ALTER TABLE ... ATTACH PARTITION
, так как требовалось защитить от:
- Параллельного добавления партиции другим процессом.
- Гонки изменения поля
relhassubclass
вpg_class
для партиционированной таблицы.
Начиная с Pangolin 6.5.0, понижен уровень блокировки для ShareUpdateExclusiveLock
для автоматического создания партиций, так как:
- для случая 1 автоматическое создание партиций сериализуется на рабочем процессе создания автопартиций, а ручное создание партиции будет захватывать
AccessExclusiveLock
, которая конфликтует сShareUpdateExclusiveLock
; - для случая 2 критичен только случай изменения
relhassubclass
наtrue
в создании автопартиции с параллельным изменением наfalse
в другом месте. Наfalse
значениеrelhassubclass
может меняться только в ходе командыANALYZE
ручного исполнения или автоочисткой, где захватывается блокировкаShareUpdateExclusiveLock
, которая будет конфликтовать сShareUpdateExclusiveLock
в создании автопартиции.
Тип блокировки также зависит от уровня изоляции текущей транзакции:
- при уровне изоляции
READ COMMITTED
(по умолчанию) для автоматического создания партиций используетсяShareUpdateExclusiveLock
; - при уровнях
REPEATABLE READ
иSERIALIZABLE
автоматически применяетсяAccessExclusiveLock
.
Логическая репликация автопартиционированных таблиц
Логическая репликация автопартиционированных таблиц работает только с параметром publish_via_partition_root
при создании публикации (CREATE PUBLICATION ... WITH (publish_via_partition_root = true)
).
Отключение автопартиционирования
Функция создания таблиц с автопартиционированием не может быть отключена.
На таблицы, созданные без указания схемы автопартиционирования, функции автопартиционирования не распространяются.
Управление
Обратная совместимость
При возврате к предыдущей версии СУБД новые партиции автоматически создаваться не будут.
Просмотр параметров автопартиционирования
Просмотр при помощи утилиты psql
В утилите psql
в вывод команд /dP
и /dPn
добавлен столбец Autopartition parameters, который содержит в текстовом виде параметры автопартиционирования для перечисленных таблиц.
Просмотр при помощи функции pg_autopartition_params
Функция pg_autopartition_params
принимает в качестве аргумента идентификатор (OID) таблицы и возвращает текст — параметры автопартиционирования для указанной таблицы.
Если таблица с указанным OID отсутствует, то выполнение прекратится с соответствующей ошибкой. Если таблица с указанным OID не является автопартиционированной, то функция вернет пустую строку.
Просмотр через системный каталог
Допускается просматривать текущие параметры автопартиционирования, расположенные в системном каталоге pg_catalog.pg_autopartition
.
Рекомендуется использовать данный способ только при однократной ручной диагностике инцидентов.
Диагностика
Обходные решения «ERROR: cannot specify default tablespace for partitioned relations»
При попытке создать партиционированную таблицу с явным указанием табличного пространства по умолчанию или с заданным параметром default_tablespace
совпадающим с табличным пространством по умолчанию для БД возникает исключительная ситуация:
-
Просмотр табличного пространства по умолчанию:
mydb=# SELECT d.datname as "Name", t.spcname as "Tablespace" FROM pg_catalog.pg_database d JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid WHERE d.datname = current_database();
Name | Tablespace
-----+-----------
mydb | myparts -
Если при создании таблицы явно указывается
TABLESPACE
как табличное пространство по умолчаниюmyparts
, выдается ошибка:mydb=# CREATE TABLE partitioned1 (
id int4 NOT NULL PRIMARY KEY,
name varchar(30) NOT NULL)
PARTITION BY RANGE (id) TABLESPACE myparts;
ERROR: cannot specify default tablespace for partitioned relations
Для предотвращения возникновения ошибки существуют обходные решения:
-
не указывайте явно табличное пространство при создании объектов в табличном пространстве по умолчанию для БД (ошибка так же не возникнет, если указать другое табличное пространство, отличное от
default_tablespace
БД):mydb=# CREATE TABLE partitioned1 (
id int4 NOT NULL PRIMARY KEY,
name varchar(30) NOT NULL)
PARTITION BY RANGE (id);
CREATE TABLEПри создании партиций
TABLESPACE
указано явно и неявно:mydb=# CREATE TABLE partitioned1_id1 PARTITION OF partitioned1 FOR VALUES FROM (MINVALUE) TO (5) TABLESPACE myparts2;
CREATE TABLE
mydb=# CREATE TABLE partitioned1_id2 PARTITION OF partitioned1 FOR VALUES FROM (5) TO (10);
CREATE TABLE
mydb=# CREATE TABLE partitioned1_id3 PARTITION OF partitioned1 FOR VALUES FROM (10) TO (MAXVALUE) TABLESPACE myparts;
CREATE TABLEВ результате они созданы в указанных
TABLESPACE
:mydb=# SELECT pg_relation_filepath('partitioned1_id1');
{{ pg_relation_filepath }}
------------------------------------------------
mydb/173793/PG_13_202206301/173794/173882
mydb=# SELECT pg_relation_filepath('partitioned1_id2');
{{ pg_relation_filepath }}
------------------------------------------------
pg_tblspc/173792/PG_13_202206301/173794/173892
mydb=# SELECT pg_relation_filepath('partitioned1_id3');
{{ pg_relation_filepath }}
------------------------------------------------
pg_tblspc/173792/PG_13_202206301/173794/173887
173792 -> /pgdata/05/tablespaces/myparts
173793 -> /pgdata/05/tablespaces/myparts2 -
всегда можно перенести таблицу в другое табличное пространство, например:
Партиция
partitioned1_id3
находится вTABLESPACE myparts
:mydb=# SELECT pg_relation_filepath('partitioned1_id3');
{{ pg_relation_filepath }}
------------------------------------------------
pg_tblspc/173792/PG_13_202206301/173794/173907Чтобы перенести ее в
TABLESPACE myparts2
:mydb=# ALTER TABLE partitioned1_id3 SET TABLESPACE myparts2;
ALTER TABLE
mydb=# SELECT pg_relation_filepath('partitioned1_id3');
{{ pg_relation_filepath }}
------------------------------------------------
pg_tblspc/173793/PG_13_202206301/173794/173917
Значение параметра default_tablespace
можно посмотреть запросом:
mydb=# show default_tablespace;
default_tablespace
--------------------
myparts
Табличное пространство по умолчанию для текущей БД можно посмотреть запросом:
SELECT d.datname as "Name", t.spcname as "Tablespace"
FROM pg_catalog.pg_database d
JOIN pg_catalog.pg_tablespace t on d.dattablespace = t.oid
WHERE d.datname = current_database();
Сценарии использования
Работа штатного механизма партиционирования
- Создайте партиционированную таблицу:
CREATE TABLE t( v INT ) PARTITION BY RANGE (v);
- Вставьте данные:
INSERT INTO t(v) VALUES(1);
В результате получена ошибка:
ERROR: no partition of relation "t" found for row
.
- Создайте партицию:
CREATE TABLE t1 PARTITION OF t FOR VALUES FROM (0) TO (10);
- Вставить данные:
INSERT INTO t(v) VALUES(1);
SELECT * FROM t;
Результат:
v
---
1
- Удалите таблицу:
DROP TABLE t;
Примеры команд для различных правил автопартиционирования
Имена автоматически создаваемых партиций (например, table_p0
, table_p1
и так далее) формируются по порядку создания, а не по значению диапазонов. Нельзя полагаться на имя партиции как на индикатор диапазона значений.
Автопартиционирование RANGE
Создание таблицы table1
с одним столбцом col1
типа INTEGER
. Партиции будут создаваться с интервалом в 10 единиц, начиная с нуля.
CREATE TABLE table1( col1 int ) AUTO PARTITION BY RANGE (col1) PERIOD(10);
Вставка первого значения 1
в столбец col1
:
INSERT INTO table1(col1) VALUES (1);
Автоматически будет создана партиция table1_p0
с диапазоном FROM (0) TO (10)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1 | f |
table1_p0 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 0 0 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 10 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
SELECT * FROM table1_p0;
col1
------
1
Вставка значения 2
в таблицу table1
:
INSERT INTO table1(col1) VALUES (2);
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1
------
1
2
Вставка значения 5
в таблицу table1
:
INSERT INTO table1(col1) VALUES (5);
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1
------
1
2
5
Вставка значения 15
в таблицу table1
:
INSERT INTO table1(col1) VALUES (15);
Автоматически будет создана партиция table1_p1
с диапазоном FROM (10) TO (20)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p1 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 10 0 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 20 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
...
SELECT * FROM table1_p1;
col1
------
15
Вставка значения 20
в таблицу table1
:
INSERT INTO table1(col1) VALUES (20);
Автоматически будет создана партиция table1_p2
с диапазоном FROM (20) TO (30)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p2 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 20 0 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 30 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
...
SELECT * FROM table1_p2;
col1
------
20
Автопартиционирование HASH
Создание таблицы table1
с одним столбцом col1
типа INTEGER
. Настройка автоматического партиционирования по методу хеша с делением по модулю 16:
CREATE TABLE table1( col1 int ) AUTO PARTITION BY HASH (col1) MODULUS (16);
Вставка первого значения 1
в столбец col1
:
INSERT INTO table1(col1) VALUES (1);
Автоматически будет создана партиция table1_p0
для значений MODULUS (16) REMAINDER (X)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1 | f |
table1_p0 | t | {PARTITIONBOUNDSPEC :strategy h :is_default false :modulus 16 :remainder 8 :listdatums <> :lowerdatums <> :upperdatums <> :locatio
n -1}
SELECT * FROM table1_p0;
col1
------
1
Вторая вставка того же значения 1
в таблицу table1
:
INSERT INTO table1(col1) VALUES (1);
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1
------
1
1
Вставка нового значения 2
в таблицу table1
:
INSERT INTO table1(col1) VALUES (2);
Автоматически будет создана партиция table1_p1
для значений MODULUS (16) REMAINDER (X)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p1 | t | {PARTITIONBOUNDSPEC :strategy h :is_default false :modulus 16 :remainder 10 :listdatums <> :lowerdatums <> :upperdatums <> :location -1}
...
SELECT * FROM table1_p1;
col1
------
2
Вставка значения 17
в таблицу table1
:
INSERT INTO table1(col1) VALUES (17);
Попадет в table1_p2
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p2 | t | {PARTITIONBOUNDSPEC :strategy h :is_default false :modulus 16 :remainder 12 :listdatums <> :lowerdatums <> :upperdatums <> :location -1}
...
SELECT * FROM table1_p2;
col1
------
17
Автопартиционирование LIST
Создание таблицы table1
с одним столбцом col1
типа INTEGER
. Партиции будут создаваться для каждого значения.
CREATE TABLE table1( col1 int ) AUTO PARTITION BY LIST (col1);
Вставка первого значения 1
в столбец col1
:
INSERT INTO table1(col1) VALUES (1);
Автоматически будет создана партиция table1_p0
для значений VALUES (1)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1 | f |
table1_p0 | t | {PARTITIONBOUNDSPEC :strategy l :is_default false :modulus 0 :remainder 0 :listdatums ({CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 1 0 0 0 0 0 0 0 ]}) :lowerdatums <> :upperdatums <> :location -1}
SELECT * FROM table1_p0;
col1
------
1
Вторая вставка того же значения 1
:
INSERT INTO table1(col1) VALUES (1);
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1
------
1
1
Вставка нового значения 2
в таблицу table1
:
INSERT INTO table1(col1) VALUES (2);
автоматически будет создана партиция table1_p1
для значений VALUES (2)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p1 | t | {PARTITIONBOUNDSPEC :strategy l :is_default false :modulus 0 :remainder 0 :listdatums ({CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 2 0 0 0 0 0 0 0 ]}) :lowerdatums <> :upperdatums <> :location -1}
...
SELECT * FROM table1_p1;
col1
------
2
Вставка значения 15
в таблицу table1
:
INSERT INTO table1(col1) VALUES (15);
Автоматически будет создана партиция table1_p2
для значений VALUES (15)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p2 | t | {PARTITIONBOUNDSPEC :strategy l :is_default false :modulus 0 :remainder 0 :listdatums ({CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 15 0 0 0 0 0 0 0 ]}) :lowerdatums <> :upperdatums <> :location -1}
...
SELECT * FROM table1_p2;
col1
------
15
Автопартиционирование RANGE со смещением
Создание таблицы table1
с одним столбцом col1
типа INTEGER
. Партиции будут создаваться с интервалом в 3 единицы, со смещением 2.
CREATE TABLE table1( col1 INTEGER ) AUTO PARTITION BY RANGE (col1) PERIOD(3) OFFSET(2);
Вставка первого значения 1
в столбец col1
:
INSERT INTO table1(col1) VALUES (1);
Автоматически будет создана партиция table1_p0
для диапазона FROM (-1) TO (2)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1 | f |
table1_p0 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ -1 -1 -1 -1 -1 -1 -1 -1 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 2 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
SELECT * FROM table1_p0;
col1
------
1
Вставка значения 2
в таблицу table1
:
INSERT INTO table1(col1) VALUES (2);
Автоматически будет создана партиция table1_p1
для диапазона FROM (2) TO (5)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p1 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 2 0 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 5 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
...
SELECT * FROM table1_p1;
col1
------
2
Вставка значения 3
в таблицу table1
:
INSERT INTO table1(col1) VALUES (3);
Попадет в table1_p1
:
SELECT * FROM table1_p1;
col1
------
2
3
Вставка значения 4
в таблицу table1
:
INSERT INTO table1(col1) VALUES (4);
Попадет в table1_p1
:
SELECT * FROM table1_p1;
col1
------
2
3
4
Вставка значения 5
в таблицу table1
:
INSERT INTO table1(col1) VALUES (5);
Автоматически будет создана партиция table1_p2
для диапазона FROM (5) TO (8)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p2 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 5 0 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 8 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
...
SELECT * FROM table1_p2;
col1
------
5
Автопартиционирование по сложному ключу партиционирования
Создание таблицы table1
с двумя столбцами col1
типа INTEGER
и col2
типа INTEGER
. Партиции будут создаваться с интервалами 10 (для столбца col1
) и 25 (для столбца col2
) со смещением 5 для столбца col2
.
CREATE TABLE table1( col1 int, col2 int ) AUTO PARTITION BY RANGE (col1, col2) PERIOD(10, 25) OFFSET(0, 5);
Вставка первых нулевых значений для столбцов col1
и col2
:
INSERT INTO table1(col1, col2) VALUES (0,0);
Автоматически будет создана партиция table1_p0
для диапазона FROM (0,-20) TO (10,5)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1 | f |
table1_p0 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 0 0 0 0 0 0 0 0 ]} :location -1} {PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ -20 -1 -1 -1 -1 -1 -1 -1 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 10 0 0 0 0 0 0 0 ]} :location -1} {PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 5 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
SELECT * FROM table1_p0;
col1 | col2
------+------
0 | 0
Вставка значений 5
и 0
в таблицу table1
:
INSERT INTO table1(col1, col2) VALUES (5,0);
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1 | col2
------+------
0 | 0
5 | 0
Вставка значений 0
и 5
в таблицу table1
:
INSERT INTO table1(col1, col2) VALUES (0,5);
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1 | col2
------+------
0 | 0
5 | 0
0 | 5
Вставка значений 10
и 10
в таблицу table1
:
INSERT INTO table1(col1, col2) VALUES (10,10);
Автоматически будет создана партиция table1_p1
для диапазона FROM (10,5) TO (20,30)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p1 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 10 0 0 0 0 0 0 0 ]} :location -1} {PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 5 0 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 20 0 0 0 0 0 0 0 ]} :location -1} {PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 30 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
...
SELECT * FROM table1_p1;
col1 | col2
------+------
10 | 10
Вставка значений 3
и 25
в таблицу table1
:
INSERT INTO table1(col1, col2) VALUES (3,25);
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1 | col2
------+------
0 | 0
5 | 0
0 | 5
3 | 25
Вставка значений 15
и 29
в таблицу table1
:
INSERT INTO table1(col1, col2) VALUES (15,29);
Попадет в table1_p1
:
SELECT * FROM table1_p1;
col1 | col2
------+------
10 | 10
15 | 29
Автопартиционирование для типа данных TIMESTAMP
Создание таблицы table1
с одним столбцом col1
типа TIMESTAMP
. Партиции будут создаваться с интервалом в 1 день, начиная в 10:30 дня и заканчивая в 10:30 (не включительно) следующего дня.
CREATE TABLE table1( col1 TIMESTAMP ) AUTO PARTITION BY RANGE (col1) PERIOD ( INTERVAL '1 day' ) OFFSET ( INTERVAL '10 hours 30 minutes' );
Вставка первого значения 2022-01-01 15:13:00
в таблицу table1
:
INSERT INTO table1(col1) VALUES ('2022-01-01 15:13:00');
Автоматически будет создана партиция table1_p0
для диапазона FROM ('2022-01-01 10:30:00') TO ('2022-01-02 10:30:00')
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1 | f |
table1_p0 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1114 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 -70 -49 -119 -127 119 2 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1114 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 26 -89 -89 -107 119 2 0 ]} :location -1}) :location -1}
SELECT * FROM table1_p0;
col1
---------------------
2022-01-01 15:13:00
Вставка значения 2022-01-01 10:31:00
в таблицу table1
:
INSERT INTO table1(col1) VALUES ('2022-01-01 10:31:00');
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1
---------------------
2022-01-01 15:13:00
2022-01-01 10:31:00
Вставка значения 2022-01-01 10:29:00
в таблицу table1
:
INSERT INTO table1(col1) VALUES ('2022-01-01 10:29:00');
Автоматически будет создана партиция table1_p1
для диапазона FROM ('2021-12-31 10:30:00') TO ('2022-01-01 10:30:00')
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p1 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1114 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 90 -8 107 109 119 2 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1114 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 -70 -49 -119 -127 119 2 0 ]} :location -1}) :location -1}
...
SELECT * FROM table1_p1;
col1
---------------------
2022-01-01 10:29:00
Автопартиционирование для типа данных DATE
Создание таблицы table1
с одним столбцом col1
типа DATE
. Партиции будут создаваться с интервалом в 1 месяц, начиная с 5-го числа:
CREATE TABLE table1( col1 DATE ) AUTO PARTITION BY RANGE (col1) PERIOD ( INTERVAL '1 month' ) OFFSET ( INTERVAL '4 days' );
Вставка первой даты 2022-01-01
в столбец col1
:
INSERT INTO table1(col1) VALUES ('2022-01-01');
Автоматически будет создана партиция table1_p0
для диапазона FROM ('2021-12-05') TO ('2022-01-05')
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1 | f |
table1_p0 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1082 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 73 31 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1082 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 104 31 0 0 0 0 0 0 ]} :location -1}) :location -1}
SELECT * FROM table1_p0;
col1
------------
2022-01-01
Вставка даты 2022-01-04
в таблицу table1
:
INSERT INTO table1(col1) VALUES ('2022-01-04');
Попадет в table1_p0
:
SELECT * FROM table1_p0;
col1
------------
2022-01-01
2022-01-04
Вставка новой даты 2022-01-05
в таблицу table1
:
INSERT INTO table1(col1) VALUES ('2022-01-05');
Автоматически будет создана партиция table1_p1
для диапазона FROM ('2022-01-05') TO ('2022-02-05')
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
-----------+----------------+---------------------------------------------------
table1_p1 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1082 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 104 31 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1082 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ -121 31 0 0 0 0 0 0 ]} :location -1}) :location -1}
...
SELECT * FROM table1_p1;
col1
------------
2022-01-05
Вставка даты 2022-01-29
в таблицу table1
:
INSERT INTO table1(col1) VALUES ('2022-01-29');
Попадет в table1_p1
:
SELECT * FROM table1_p1;
col1
------------
2022-01-05
2022-01-29
Вставка даты 2022-02-04
в таблицу table1
:
INSERT INTO table1(col1) VALUES ('2022-02-04');
Попадет в table1_p1
:
SELECT * FROM table1_p1;
col1
------------
2022-01-05
2022-01-29
2022-02-04
Вложенное (каскадное) автопартиционирование
Создание таблицы table1
с двумя столбцами col1
типа INTEGER
и col2
типа INTEGER
. Партиции будут создаваться с интервалом в 10, которые, в свою очередь, будут являться партиционированными таблицами, для которых будут создаваться партиции по модулю 16:
CREATE TABLE table1( col1 INTEGER , col2 INTEGER ) AUTO PARTITION BY RANGE (col1) PERIOD(10) AUTO PARTITION BY HASH (col2) MODULUS (16);
Вставка первых значений 5
для col1
и 10
для col2
:
INSERT INTO table1(col1,col2) VALUES (5,10);
Автоматически будет создана партиция table1_p0
для диапазона FROM (0) TO (10)
с автопартиционированием AUTO PARTITION BY HASH (col2) MODULUS (16)
и автоматически будет создана партиция table1_p0_p0
для таблицы table1_p0
c MODULUS (16) REMAINDER(X)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
--------------+----------------+------------------------------------------------
table1 | f |
table1_p0 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 0 0 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 10 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
table1_p0_p0 | t | {PARTITIONBOUNDSPEC :strategy h :is_default false :modulus 16 :remainder 7 :listdatums <> :lowerdatums <> :upperdatums <> :location -1}
SELECT * FROM table1_p0;
col1 | col2
------+------
5 | 10
SELECT * FROM table1_p0_p0;
col1 | col2
------+------
5 | 10
Вставка значений 8
и 11
в таблицу table1
:
INSERT INTO table1(col1,col2) VALUES (8,11);
Автоматически будет создана партиция table1_p0_p1
для таблицы table1_p0
c MODULUS (16) REMAINDER(X)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
--------------+----------------+------------------------------------------------
table1_p0_p1 | t | {PARTITIONBOUNDSPEC :strategy h :is_default false :modulus 16 :remainder 1 :listdatums <> :lowerdatums <> :upperdatums <> :location -1}
...
SELECT * FROM table1_p0;
col1 | col2
------+------
8 | 11
5 | 10
SELECT * FROM table1_p0_p1;
col1 | col2
------+------
8 | 11
Вставка значений 8
и 26
в таблицу table1
:
INSERT INTO table1(col1,col2) VALUES (8,26);
Автоматически будет создана партиция table1_p0_p2
для таблицы table1_p0
c MODULUS (16) REMAINDER(X)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
--------------+----------------+------------------------------------------------
table1_p0_p2 | t | {PARTITIONBOUNDSPEC :strategy h :is_default false :modulus 16 :remainder 0 :listdatums <> :lowerdatums <> :upperdatums <> :location -1}
...
SELECT * FROM table1_p0;
col1 | col2
------+------
8 | 26
8 | 11
5 | 10
SELECT * FROM table1_p0_p2;
col1 | col2
------+------
8 | 26
Вставка значений 12
и 10
в таблицу table1
:
INSERT INTO table1(col1,col2) VALUES (12,10);
Автоматически будет создана партиция table1_p1
для диапазона FROM (10) TO (20)
с автопартиционированием AUTO PARTITION BY HASH (col2) MODULUS (16)
и автоматически будет создана партиция table1_p1_p0
для таблицы table1_p1
c MODULUS (16) REMAINDER(X)
:
SELECT relname, relispartition, relpartbound FROM pg_class WHERE relname LIKE '%table1%';
relname | relispartition | relpartbound
--------------+----------------+------------------------------------------------
table1_p1 | t | {PARTITIONBOUNDSPEC :strategy r :is_default false :modulus 0 :remainder 0 :listdatums <> :lowerdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 10 0 0 0 0 0 0 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 23 :consttypmod -1 :constcollid 0 :constlen 4 :constbyval true :constisnull false :location -1 :constvalue 4 [ 20 0 0 0 0 0 0 0 ]} :location -1}) :location -1}
table1_p1_p0 | t | {PARTITIONBOUNDSPEC :strategy h :is_default false :modulus 16 :remainder 7 :listdatums <> :lowerdatums <> :upperdatums <> :location -1}
...
SELECT * FROM table1_p1;
col1 | col2
------+------
12 | 10
SELECT * FROM table1_p1_p0;
col1 | col2
------+------
12 | 10