Нативное интервальное партиционирование#

Функциональность доступна только для редакций Enterprise и Enterprise для ERP-систем.

Описание#

Нативное интервальное партиционирование (или автопартиционирование) — это механизм, который позволяет автоматически создавать партиции (секции) для таблиц при перемещении или вставке новых данных со значениями, не подходящими под критерий данных для существующих партиций.

Автопартиционирование может быть вложенным. При вложенном автопартиционировании все создаваемые таблицы, кроме самой последней по уровню вложенности, являются партиционированными таблицами. Реальные данные в такой схеме хранятся только в самой последней таблице. Автопартиционирование создаст необходимые таблицы на всех уровнях вложенности.

При удалении или перемещении данных пустые партиции не удаляются.

Автопартиционирование работает следующим образом. При создании партиционированной таблицы (корневой таблицы) указываются параметры автопартиционирования. При вставке или изменении данных СУБД пытается найти подходящую партицию. Если подходящая партиция не найдена, то происходит поиск правила автопартиционирования для таблицы. Если правило найдено, то происходит создание новой таблицы и затем повторная попытка вставки данных. Данный процесс может повторяться рекурсивно для вложенного автопартиционирования.

Автопартиционирование не исключает возможности управлять партициями вручную. При этом все стандартные механизмы в СУБД продолжают работать. Однако нужно учитывать потенциальное пересечение интервалов партиций, если партиции, создаваемые вручную, частично пересекаются с диапазонами автоматически создаваемых партиций. Для исключения пересечения необходимо убедиться, что настройки автопартиционирования не приведут к созданию партиций, имеющих пересекающиеся диапазоны данных с существующими партициями.

Нативное интервальное партиционирование доступно для следующих стратегий партиционирования:

  • LIST – партиция будет автоматически создаваться для каждого значения из списка;

  • HASH – партиции будут создаваться автоматически для каждого остатка (remainder) от деления значения хеш-функции на задаваемый делитель (modulus);

  • RANGE – партиции будут задаваться автоматически для каждого интервала, задаваемого в процессе создания таблицы при помощи нового синтаксиса.

Синтаксис команды создания таблицы с включенным автопартиционированием#

Автопартиционирование настраивается в момент создания таблицы.

При создании таблицы через 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 согласно стандарту рассчитывается по UTC).

При создании таблицы с недельным интервалом без указания OFFSET границы партиций будут начинаться с субботы, так как дата 2000-01-01, используемая как точка отсчета, приходится на субботу.

Чтобы задать недельный интервал с понедельника по воскресенье, необходимо указать точку отсчета 2001-01-01, которая приходится на понедельник:

AUTO PARTITION BY RANGE (col1) PERIOD ('1 week'::interval) OFFSET ('2001-01-01 00:00:00'::timestamp)

Для улучшения поддержки пользователя добавлена возможность осуществлять партиционирование по 00:00:00 указанной таймзоны (параметр autopartition.default_timezone), когда это возможно (для интервалов партиционирования: ежедневно, ежемесячно, ежегодно и так далее, кратных им). Для управления этой функциональностью существуют параметры конфигурации autpartition.enable_shift и autopartition.default_timezone.

  • autpartition.enable_shift (значение по умолчанию – выключен). Включает функциональность партиционирования по 00:00:00 по указанной таймзоне.

  • autopartition.default_timezone (значение по умолчанию отсутствует). При задании параметра идет проверка на реальность таймзоны, как для оригинального параметра timezone в конфигурационном файле. Если параметр не задан, то берется значение setting из pg_files_settings, где колонка name = timezone, а если оно не задано, то берется таймзона GMT.

Формулы, по которым вычисляется диапазон партиции для значения 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 новая партиция создается для значения остатка (REMAINDER) от новых данных по модулю (MODULUS), указанному в параметрах автопартиционирования. Модуль определяет количество возможных партиций. При вставке или изменении данных рассчитывается хеш-значение для данных. Далее производится вычисление остатка (REMAINDER) от деления от этого значения по указанному модулю. Этот остаток определяет партицию, в которую попадут данные.

При включенном автопартиционировании в случае необходимости будут создаваться партиции с указанным MODULUS и рассчитанным REMAINDER для новых данных.

Правила автопартиционирования для стратегии LIST#

Для LIST партиций параметры отсутствуют.

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

Именование партиций#

Новые партиции создаются с именем, состоящим из:

  • имени вышестоящей по уровню вложенности таблицы;

  • символов «_p»;

  • числа — условного номера партиции, в типичной ситуации равному порядковому номеру в порядке создания партиций, начиная с нуля.

Блокировки при автопартиционировании#

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

В версиях Pangolin до 6.5.0 перед добавлением партиции выполнялась блокировка AccessExclusiveLock на партиционированную таблицу, которая препятствовала дальнейшему прогрессу других сессий.

Выполнялась именно блокировка AccessExclusiveLock по аналогии с ALTER TABLE ... ATTACH PARTITION, так как требовалось защитить от:

  1. Параллельного добавления партиции другим процессом.

  2. Гонки изменения поля 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)).

Отключение автопартиционирования#

Функция создания таблиц с автопартиционированием не может быть отключена.

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

Перекрытие партиций при автопартиционировании#

В ходе эксплуатации обнаружились перекрытия партиций, появляющиеся в частности из-за смены таймзон. Для решения этой проблемы был введен новый параметр конфигурации autpartition.overlap_correction (значение по умолчанию – выключен). Он включает подрезку (уменьшение) размера партиций при обнаружении перекрытия. Включение его применяется для всех объектов базы данных, как существующих, так и для вновь создаваемых, но только для случая с одним ключом партиционирования с типом TIMESTAMPTZ (когда решение задачи подрезки однозначно).

Управление#

Обратная совместимость#

При возврате к предыдущей версии СУБД новые партиции автоматически создаваться не будут.

Просмотр параметров автопартиционирования#

Просмотр при помощи утилиты psql#

В утилите psql в вывод команд /dP и /dPn добавлен столбец Autopartition parameters, который содержит в текстовом виде параметры автопартиционирования для перечисленных таблиц.

Просмотр при помощи функции pg_autopartition_params#

Функция pg_autopartition_params принимает в качестве аргумента идентификатор (OID) таблицы и возвращает текст — параметры автопартиционирования для указанной таблицы.

Если таблица с указанным OID отсутствует, то выполнение прекратится с соответствующей ошибкой. Если таблица с указанным OID не является автопартиционированной, то функция вернет пустую строку.

Просмотр через системный каталог#

Допускается просматривать текущие параметры автопартиционирования, расположенные в системном каталоге pg_catalog.pg_autopartition.

Рекомендуется использовать данный способ только при однократной ручной диагностике инцидентов.

Автоматическое применение параметров хранения при автопартиционировании таблиц#

Функциональность доступна только для редакций Enterprise и Enterprise для ERP-систем.

Реализована возможность задавать параметры хранения (reloptions) на уровне автопартиционированной таблицы. Эти параметры автоматически применяются ко всем вновь создаваемым партициям (секциям) без необходимости ручной настройки каждой из них.

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

Также реализовано автоматическое наследование табличного пространства (TABLESPACE): новая партиция создается в том же табличном пространстве, что и ее родитель, если иное не указано явно. При восстановлении из дампа (pg_dump, pg_restore, pg_upgrade) секции создаются в табличных пространствах, указанных в их DDL, даже если параметры родительской таблицы были изменены.

Функциональность применяется только к партициям, создаваемым автоматически. При ручном создании или присоединении партиций (CREATE TABLE ... PARTITION OF, ALTER TABLE ... ATTACH PARTITION) параметры не применяются.

Ограничения#

Ниже приведены ограничения, которые необходимо учитывать при использовании механизма автоматического применения параметров хранения в автопартиционировании:

  • Автоматически применяются только параметры хранения. Наследование других свойств (например, CHECK-ограничений, настроек безопасности) не гарантируется.

  • Параметры применяются только при создании новых партиций. Существующие партиции не изменяются.

  • Не поддерживается автоматическое применение параметров, начинающихся с префикса toast. (например, toast.autovacuum_enabled).

  • Параметры применяются только к конечным партициям. Промежуточные партиционированные таблицы служат только для транзита параметров.

Список параметров хранения, применяемых автоматически#

В таблице приведен перечень параметров reloptions, которые автоматически наследуются новыми партициями при использовании автопартиционирования.

Поддерживаемые параметры хранения для автопартиционирования#

Название

Тип

fillfactor

integer

toast_tuple_target

integer

parallel_workers

integer

autovacuum_enabled

boolean

vacuum_index_cleanup

enum

vacuum_truncate

boolean

autovacuum_vacuum_threshold

integer

autovacuum_vacuum_scale_factor

float

autovacuum_vacuum_insert_threshold

integer

autovacuum_vacuum_insert_scale_factor

float

autovacuum_analyze_threshold

integer

autovacuum_analyze_scale_factor

float

autovacuum_vacuum_cost_delay

float

autovacuum_vacuum_cost_limit

integer

autovacuum_freeze_min_age

integer

autovacuum_freeze_max_age

integer

autovacuum_freeze_table_age

integer

autovacuum_multixact_freeze_min_age

integer

autovacuum_multixact_freeze_max_age

integer

autovacuum_multixact_freeze_table_age

integer

log_autovacuum_min_duration

integer

Ручная настройка базовой таймзоны для автопартиционирования#

Для реализации новой функциональности партиционирования по 00:00:00 по указанной таймзоне была использована колонка offsets таблицы pg_autopartition, где базовая таймзона, по которой будут создаваться партиции, сохраняется в виде текста, упакованного в node_tree структуру сериализации. Таким образом для любой автопартиционированной таблицы есть возможность задать/изменить значение таймзоны, по которой будут рассчитываться границы партиций при автопартиционировании по ключу типа TIMESTAMPTZ. Это может быть оправдано, только если при создании таблицы параметр OFFSET не был задан, в противной случае изменение существующего значения смещения приведет к непредвиденному расчету границ партиций. Для таблиц, при создании которых не был указан OFFSET, значение колонки Autopartition parameters вывод команды /dP и /dPn выглядит следующим образом:

SET autopartition.enable_shift TO off;
CREATE TABLE table1( col1 TIMESTAMPTZ ) AUTO PARTITION BY RANGE (col1) PERIOD ( INTERVAL '1 day' );
\dPn table1
                                                                       List of partitioned relations
 Schema |  Name  |  Owner   |       Type        | Parent name | Table |                                      Autopartition parameters                                       
--------+--------+----------+-------------------+-------------+-------+-----------------------------------------------------------------------------------------------------
 public | table1 | postgres | partitioned table |             |       | AUTO PARTITION BY RANGE (col1) PERIOD ('1 day'::interval)

А в представлении pg_autopartition в колонке offsets для данной таблицы будет выведено:

SELECT rel, offsets FROM pg_autopartition WHERE rel = 'table1'::regclass;

   rel   | offsets 
---------+---------
 1051859 | (<>)

В случае, если при создании таблицы параметр autopartition.enable_shift включен и таймзона сервера была выставлена в Europe/Moscow, то значение колонки Autopartition parameters вывода команд /dP и /dPn выглядит следующим образом:

\dPn table1
                                                                       List of partitioned relations
 Schema |  Name  |  Owner   |       Type        | Parent name | Table |                                      Autopartition parameters                                       
--------+--------+----------+-------------------+-------------+-------+-----------------------------------------------------------------------------------------------------
 public | table1 | postgres | partitioned table |             |       | AUTO PARTITION BY RANGE (col1) PERIOD ('1 day'::interval) OFFSET ('Europe/Moscow'::pg_catalog.text)

Заданный OFFSET ('Europe/Moscow'::pg_catalog.text) показывает таймзону, в которой будут рассчитываться границы создаваемых партиций для table1. В pg_autopartition это значение выглядит следующим образом:

SELECT rel, offsets FROM pg_autopartition WHERE rel = 'table1'::regclass;
   rel   |                                                                                              offsets                                                                                       
       
---------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------
 1051850 | ({CONST :consttype 25 :consttypmod -1 :constcollid 0 :constlen -1 :constbyval false :constisnull false :location -1 :constvalue 17 [ 68 0 0 0 69 117 114 111 112 101 47 77 111 115 99 111 1
19 ]})

Таким образом, можно изменить таймзону, по которой будут рассчитываться границы партиций, выполнив запрос UPDATE для колонки offsets представления pg_autopartition. Например, при изменении таймзоны на Asia/Novosibirsk:

UPDATE pg_autopartition SET offsets = '({CONST :consttype 25 :consttypmod -1 :constcollid 0 :constlen -1 :constbyval false :constisnull false :location -1 :constvalue 20 [ 80 0 0 0 65 115 105 97 47 78 111 118 111 115 105 98 105 114 115 107 ]})' where rel = 'table1'::regclass;

Результатом будет следующий вывод:

\dPn table1
                                                                         List of partitioned relations
 Schema |  Name  |  Owner   |       Type        | Parent name | Table |                                        Autopartition parameters                                        
--------+--------+----------+-------------------+-------------+-------+--------------------------------------------------------------------------------------------------------
 public | table1 | postgres | partitioned table |             |       | AUTO PARTITION BY RANGE (col1) PERIOD ('1 day'::interval) OFFSET ('Asia/Novosibirsk'::pg_catalog.text)

Диагностика#

Обходные решения «ERROR: cannot specify default tablespace for partitioned relations»#

При попытке создать партиционированную таблицу с явным указанием табличного пространства по умолчанию или с заданным параметром default_tablespace совпадающим с табличным пространством по умолчанию для БД возникает исключительная ситуация:

  1. Просмотр табличного пространства по умолчанию:

    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
    
  2. Если при создании таблицы явно указывается 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;

```text
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();

Ошибка «ERROR: auto-created partition overlaps existing partition»#

При возникновении ошибки перекрытия партиций «ERROR: auto-created partition overlaps existing partition» вставка данных невозможна, происходит откат текущей транзакции. Наиболее критичной эта ошибка является для типа TIMESTAMPTZ из-за изменений сдвига по времени таймзоны из-за принятых законов.

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

2026-02-11 10:18:57.736 MSK [4058695] WARNING:  Conflict on partition creation: partition "test_dba_p2" would overlap partition "test_dba_p0"
        test_dba_p2 FOR VALUES FROM ('2010-10-30 06:00:00+07') TO ('2010-10-31 06:00:00+06')
        test_dba_p0 FOR VALUES FROM ('2010-10-29 07:00:00+07') TO ('2010-10-30 07:00:00+07')

Диагностические сообщения выводятся для всех типов поддерживаемых при автопартиционировании данных.

Для исправления указанной ошибки введен механизм уменьшения (подрезания) вновь создаваемых партиций. Для его включения используется параметр autpartition.overlap_correction.

Следует отметить, что при автопартиционировании с включенным параметром autopartition.enable_shift уменьшение (подрезка) партиций также происходит, но только для тех таблиц, которые были созданы в то время, когда autopartition.enable_shift был включен. И даже после его отключения партиции этих таблиц будут «подрезаться» в случае возникновения перекрытия.

Сценарии использования#

Работа штатного механизма партиционирования#

  1. Создайте партиционированную таблицу:

    CREATE TABLE t( v INT ) PARTITION BY RANGE (v);
    
  2. Вставьте данные:

    INSERT INTO t(v) VALUES(1);
    

    В результате получена ошибка:

    ERROR: no partition of relation "t" found for row`
    
  3. Создайте партицию:

    CREATE TABLE t1 PARTITION OF t FOR VALUES FROM (0) TO (10);
    
  4. Вставить данные:

    INSERT INTO t(v) VALUES(1);
    SELECT * FROM t;
    

    Результат:

    v
    ---
    1
    
  5. Удалите таблицу:

    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}
...

```sql
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 <> :location -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

Автопартиционирование для типа данных TIMESTAMPTZ#

Создание таблицы table1 с одним столбцом col1 типа TIMESTAMPTZ.

CREATE TABLE table1( col1 TIMESTAMPTZ ) AUTO PARTITION BY RANGE (col1) PERIOD ( INTERVAL '1 day' );

По умолчанию, партиции будут создаваться с интервалом в 1 день, в таймзоне UTC.

Установка первого значения 2025-10-01 01:00:00 в таблицу table1 из сессии в таймзоне Europe/Moscow:

INSERT INTO table1(col1) VALUES ('2025-10-01 01:00:00');

Автоматически будет создана партиция table1_p0 для диапазона FROM ('2025-09-30 03:00:00+03') TO ('2025-10-01 03:00:00+03'):

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 1184 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 -128 -86 51 -8 -30 2 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1184 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 -32 -127 81 12 -29 2 0 ]} :location -1}) :location -1}
SELECT * FROM table1_p0;
        col1
---------------------
 2025-10-01 01:00:00+03

Заданное значение попало в предыдущий день от заданной даты, так как расчет идет по тайзоне UTC, а данные вставляются из тайзоны Europe/Moscow, между которыми разница 3 часа в данном примере. Т.е. значение 2025-10-01 01:00:00 по таймзоне Europe/Moscow равно значению 2025-09-30 22:00:00 по UTC.

Установка значения 2025-10-01 04:00 в таблицу table1:

INSERT INTO table1(col1) VALUES ('2025-10-01 04:00');

Автоматически будет создана партиция table1_p1 для диапазона FROM ('2025-10-01 03:00:00+03') TO ('2025-10-02 03:00:00+03'):

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 1184 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 -32 -127 81 12 -29 2 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1184 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 64 89 111 32 -29 2 0 ]} :location -1}) :location -1}
...
SELECT * FROM table1_p1;
        col1
---------------------
 2025-10-01 04:00:00+03

Для того, чтобы расчет начала и конца партиций велся по определенной таймзоне, необходимо включить параметр autopartition.enable_shift. В этом случае значение таймзоны для расчета границ будет равно значению таймзоны, которые выставлено на сервере. Также можно воспользоваться параметром autopartition.default_timezone, с помощью которого можно задать таймзону для расчета границ при автопартиционировании, как на уровне сервера, так и для отдельной сессии пользователя.

Задайте параметры autopartition.enable_shift и autopartition.default_timezone для текущей сессии:

SET autopartition.enable_shift TO on;
SET autopartition.default_timezone TO 'Europe/Moscow';

Создание таблицы table1 с одним столбцом col1 типа TIMESTAMPTZ.

CREATE TABLE table1( col1 TIMESTAMPTZ ) AUTO PARTITION BY RANGE (col1) PERIOD ( INTERVAL '1 day' );

Теперь партиции будут создаваться с интервалом в 1 день, в таймзоне Europe/Moscow.

Установка первого значения 2025-10-01 01:00:00 в таблицу table1 из сессии в таймзоне Europe/Moscow:

INSERT INTO table1(col1) VALUES ('2025-10-01 01:00:00');

Автоматически будет создана партиция table1_p0 для диапазона FROM ('2025-10-01 00:00:00+03') TO ('2025-10-02 00:00:00+03'):

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 1184 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 -12 -58 -51 9 -29 2 0 ]} :location -1}) :upperdatums ({PARTITIONRANGEDATUM :kind 0 :value {CONST :consttype 1184 :consttypmod -1 :constcollid 0 :constlen 8 :constbyval true :constisnull false :location -1 :constvalue 8 [ 0 84 -98 -21 29 -29 2 0 ]} :location -1}) :location -1}
SELECT * FROM table1_p0;
        col1
---------------------
 2025-10-01 01:00:00+03

Установка значения 2025-10-01 04:00:00 в таблицу table1:

INSERT INTO table1(col1) VALUES ('2025-10-01 04:00:00');

Попадет в table1_p0:

SELECT * FROM table1_p0;

        col1
---------------------
 2025-10-01 01:00:00+03
 2025-10-01 04:00:00+03

Вложенное (каскадное) автопартиционирование#

Создание таблицы 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