Партиционирование
Обзор
Партиционирование (partitioning) — это способ повышения производительности запросов за счет логического разбиения больших таблиц (например, таблиц фактов) на небольшие части, называемые партициями (partitions). Партиционирование позволяет оптимизаторам запросов сканировать ограниченное число строк в таблице (на основе условий предикатов) вместо чтения всего содержимого таблицы.
Принадлежность каждой новой записи таблицы к той или иной партиции определяется на основе значения ключа партиционирования (partition key) — столбца (или набора столбцов в случае многоуровневого партиционирования), который выбирается при создании партиционированной таблицы.
Партиционирование выполняется на логическом уровне. В отличие от распределения данных, партиционирование не делит таблицу физически. Как партиционированные, так и непартиционированные таблицы распределяются между сегментами кластера.
Несмотря на преимущества партиционирования, далеко не все таблицы подходят для его применения. Также следует учитывать: чем больше партиций создается, тем медленнее может стать управление кластером в дальнейшем. Ниже перечислены условия, при выполнении которых партиционирование может существенно повысить производительность запросов. Используйте партиционирование, если все или большинство описанных условий применимы к базе данных:
-
Существует большая таблица фактов. Таблицы фактов с миллионами строк являются хорошими кандидатами для применения партиционирования. Партиционирование небольших таблиц с тысячами строк и меньше, напротив, малоэффективно.
-
Текущая скорость выполнения запросов неудовлетворительна. Применяйте партиционирование только к тем таблицам, запросы к которым выполняются значительно медленнее, чем требуется. Это общая рекомендация перед использованием любых методов оптимизации.
-
Существует столбец, на основе которого можно разбить таблицу на примерно одинаковые части. Старайтесь выбирать ключ партиционирования таким образом, чтобы количество строк в каждой партиции было приблизительно одинаковым. Чем равномернее таблица будет разбита на небольшие части, тем больше преимуществ можно получить. Например, разбив таблицу на 10 одинаковых партиций, можно добиться увеличения скорости выполнения запросов в 10 раз по сравнению с непартиционированной таблицей (при условии, что ключ партиционирования используется в предикатах запросов — см. пункт ниже).
-
Большинство запросов, требующих ускорения, используют ключ партицинирования в предикатах. Партиционирование приносит пользу только в случае, если оптимизаторы запросов могут отобрать нужные партиции на основе предикатов, используемых в запросах. Запросы, сканирующие все партиции, могут работать даже медленнее, чем до применения партиционирования. Убедитесь, что планы выполнения запросов содержат partition elimination (сканирование ограниченного числа партиций).
-
Существуют бизнес-требования к хранению исторических данных. Партиционирование отлично справляется с задачей хранения данных за ограниченный период времени. Например, если в базе данных требуется хранить информацию за последние 12 месяцев, можно легко удалять партиции с устаревшими данными и загружать актуальные данные в новые партиции.
Создание партиционированной таблицы
Синтаксис
Для создания партиционированной таблицы используется команда CREATE TABLE с выражением PARTITION BY
(и опционально SUBPARTITION BY
). Синтаксис команды зависит от типа партиционирования: range, list или комбинация обоих типов (multi-level):
-
Партиционирование на основе диапазонов (range). Партиционирование с типом range осуществляет разделение данных на основе числовых или временных (date/timestamp) диапазонов. Необходимо использовать выражение
PARTITION BY RANGE
, после него указать в скобках ключ партиционирования и затем в отдельных скобках описать интервалы для партиций, используя ключевые словаSTART
иEND
. ВыраженияINCLUSIVE
иEXCLUSIVE
используются в связке сSTART
иEND
для указания того, должны ли попадать в соответствующий диапазон граничные значения. По умолчанию значения, указанные с помощьюSTART
, включаются в диапазон; значения, определенные с помощьюEND
— нет.Существует два способа определения range-партиций — автоматически и вручную:
-
Автоматическое формирование партиций. Чтобы сгенерировать партиции автоматически, необходимо использовать ключевые слова
START
иEND
один раз для определения границ всего диапазона. Затем требуется указать выражениеEVERY
для определения шага инкремента. При использовании диапазона дат это выражение требует указания единицы измерения:day
,month
илиyear
(например,EVERY(INTERVAL '1 month')
). Для числовых диапазонов вводится только число (например,EVERY(1)
). СУБД автоматически выполнит разбиение всего указанного интервала на нужное число партиций в соответствии с выбранным шагом. -
Определение партиций вручную. Альтернативный способ описания range-партиций — вручную. В этом случае необходимо описать спецификации всех партиций через запятую в круглых скобках после указания ключа партиционирования. Каждая спецификация начинается с выражения
PARTITION <partition_name>
, где<partition_name>
— имя, используемое вместо автоматически генерируемого номера в полном имени партиции. Оставшаяся часть спецификации содержит выраженияSTART
иEND
, определяющие границы каждой партиции. Обратите внимание, что указаниеEND
требуется только для партиции, идущей в списке последней.
-
-
Партиционирование на основе списков значений (list). Партиционирование с типом list выполняет разделение данных на основе предопределенного списка значений ключа партиционирования. Необходимо использовать выражение
PARTITION BY LIST
, после него указать в скобках ключ партиционирования и затем в отдельных скобках описать спецификации партиций через запятую. Каждая спецификация использует следующий шаблон:PARTITION <partition_name> VALUES (<list_value> [,…])
, где<partition_name>
— имя, используемое вместо автоматически генерируемого номера в полном имени партиции;<list_value>
— значения ключа партиционирования, соответствующие текущей партиции. -
Многоуровневое партиционирование (multi-level). Партиционирование с типом multi-level — это комбинация партиционирования с типом range и/или list на нескольких уровнях. Оно позволяет разделять партиции первого уровня на сабпартиции (subpartitions) второго уровня, а их в свою очередь — на сабпартиции третьего уровня и так далее. Выражение
PARTITION BY
(RANGE
илиLIST
) используется для определения ключа партиционирования на первом уровне иерархии; выражениеSUBPARTITION BY
(RANGE
илиLIST
) — на всех нижележащих уровнях. Спецификации сабпартиций не отличаются от партиций, за исключением использования ключевого словаSUBPARTITION
вместоPARTITION
.Возможны два способа определения сабпартиций — с использованием шаблона (subpartition template) и без него:
-
Использование subpartition template. В этом случае спецификации сабпартиций каждого уровня описываются только один раз с использованием выражения
SUBPARTITION TEMPLATE
. Каждый шаблон заполняется после соответствующего выраженияSUBPARTITION BY
. Использование шаблонов гарантирует, что все партиции будут иметь одинаковую структуру, включая те, что будут добавлены после создания таблицы. -
Определение сабпартиций вручную. В этом случае каждая партиция и ее сабпартиции описываются индивидуально. Вначале требуется перечислить все ключи партиционирования с использованием выражений
PARTITION BY
иSUBPARTITION BY
, а затем описать спецификации партиций и сабпартиций. Их иерархия определяется с помощью вложенных круглых скобок.
-
Для всех видов партиционирования возможно указание партиции по умолчанию (default partition) с использованием выражения DEFAULT PARTITION
(или DEFAULT SUBPARTITION
для сабпартиций) сразу после спецификации партиции (или сабпартиции). Этот тип партиций предназначен для хранения данных, которые не попадают в указанный диапазон (или список) значений.
ВАЖНО
|
Примеры
Следующий пример показывает создание двенадцати партиций на основе диапазона дат — по одной партиции на каждый месяц 2022
года. Также создается партиция по умолчанию.
CREATE TABLE book_order
(id INT,
book_id INT,
client_id INT,
book_count SMALLINT,
order_date DATE,
CHECK(book_count >= 1)
)
WITH (appendoptimized=true, orientation=row, compresstype=ZLIB, compresslevel=5)
DISTRIBUTED BY(id)
PARTITION BY RANGE(order_date)
(START(date '2022-01-01') INCLUSIVE
END(date '2023-01-01') EXCLUSIVE
EVERY(INTERVAL '1 month'),
DEFAULT PARTITION other);
Результат:
NOTICE: CREATE TABLE will create partition "book_order_1_prt_other" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_2" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_3" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_4" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_5" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_6" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_7" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_8" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_9" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_10" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_11" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_12" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_13" for table "book_order" CREATE TABLE
Следующий пример показывает создание десяти партиций на основе числового диапазона — по одной партиции на каждый год с 2013
по 2022
. Также создается партиция по умолчанию. По сравнению с партиционированием на основе диапазона дат, нет необходимости явно указывать тип данных в выражениях START
и END
, а также выбирать единицу измерения в выражении EVERY
. В остальном синтакис тот же.
CREATE TABLE book
(id INT,
title TEXT,
author_id INT NOT NULL,
public_year SMALLINT NULL,
type_id INT NOT NULL,
cover_id INT NOT NULL)
WITH (appendoptimized=true, orientation=row, compresstype=ZLIB, compresslevel=5)
DISTRIBUTED BY(id)
PARTITION BY RANGE(public_year)
(START(2013)
END(2023)
EVERY(1),
DEFAULT PARTITION other);
Результат:
NOTICE: CREATE TABLE will create partition "book_1_prt_other" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_2" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_3" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_4" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_5" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_6" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_7" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_8" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_9" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_10" for table "book" NOTICE: CREATE TABLE will create partition "book_1_prt_11" for table "book" CREATE TABLE
Следующий пример показывает создание таблицы book_order_manual
со структурой полностью идентичной таблице book_order
, созданной выше — за исключением того, что каждая партиция теперь описывается отдельно.
CREATE TABLE book_order_manual
(id INT,
book_id INT,
client_id INT,
book_count SMALLINT,
order_date DATE,
CHECK(book_count >= 1)
)
WITH (appendoptimized=true, orientation=row, compresstype=ZLIB, compresslevel=5)
DISTRIBUTED BY(id)
PARTITION BY RANGE(order_date)
(PARTITION Jan22 START(date '2022-01-01') INCLUSIVE,
PARTITION Feb22 START(date '2022-02-01') INCLUSIVE,
PARTITION Mar22 START(date '2022-03-01') INCLUSIVE,
PARTITION Apr22 START(date '2022-04-01') INCLUSIVE,
PARTITION May22 START(date '2022-05-01') INCLUSIVE,
PARTITION Jun22 START(date '2022-06-01') INCLUSIVE,
PARTITION Jul22 START(date '2022-07-01') INCLUSIVE,
PARTITION Aug22 START(date '2022-08-01') INCLUSIVE,
PARTITION Sep22 START(date '2022-09-01') INCLUSIVE,
PARTITION Oct22 START(date '2022-10-01') INCLUSIVE,
PARTITION Nov22 START(date '2022-11-01') INCLUSIVE,
PARTITION Dec22 START(date '2022-12-01') INCLUSIVE END(date '2023-01-01') EXCLUSIVE,
DEFAULT PARTITION other);
Результат:
NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_other" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_jan22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_feb22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_mar22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_apr22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_may22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_jun22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_jul22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_aug22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_sep22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_oct22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_nov22" for table "book_order_manual" NOTICE: CREATE TABLE will create partition "book_order_manual_1_prt_dec22" for table "book_order_manual" CREATE TABLE
Следующий пример показывает создание таблицы book_manual
со структурой полностью идентичной таблице book
, созданной выше — за исключением того, что каждая партиция теперь описывается отдельно.
CREATE TABLE book_manual
(id INT,
title TEXT,
author_id INT NOT NULL,
public_year SMALLINT NULL,
type_id INT NOT NULL,
cover_id INT NOT NULL)
WITH (appendoptimized=true, orientation=row, compresstype=ZLIB, compresslevel=5)
DISTRIBUTED BY(id)
PARTITION BY RANGE(public_year)
(PARTITION Year2013 START(2013),
PARTITION Year2014 START(2014),
PARTITION Year2015 START(2015),
PARTITION Year2016 START(2016),
PARTITION Year2017 START(2017),
PARTITION Year2018 START(2018),
PARTITION Year2019 START(2019),
PARTITION Year2020 START(2020),
PARTITION Year2021 START(2021),
PARTITION Year2022 START(2022) END(2023),
DEFAULT PARTITION other);
Результат:
NOTICE: CREATE TABLE will create partition "book_manual_1_prt_other" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2013" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2014" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2015" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2016" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2017" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2018" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2019" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2020" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2021" for table "book_manual" NOTICE: CREATE TABLE will create partition "book_manual_1_prt_year2022" for table "book_manual" CREATE TABLE
Следующий пример показывает создание двух партиций на основе значений столбца gender
. Также добавляется партиция по умолчанию.
CREATE TABLE client (id INT, name TEXT, gender CHAR(1))
DISTRIBUTED BY (id)
PARTITION BY LIST (gender)
(PARTITION girls VALUES ('F'),
PARTITION boys VALUES ('M'),
DEFAULT PARTITION other);
Результат:
NOTICE: CREATE TABLE will create partition "client_1_prt_girls" for table "client" NOTICE: CREATE TABLE will create partition "client_1_prt_boys" for table "client" NOTICE: CREATE TABLE will create partition "client_1_prt_other" for table "client" CREATE TABLE
Следующий пример демонстрирует трехуровневое партиционирование. Команда добавляет три партиции с типом range на первом уровне иерархии, затем разделяет их на три сабпартиции на втором уровне — в зависимости от значений столбца region
. Эти сабпартиции, в свою очередь, разделяются на три сабпартиции на третьем уровне — на основе значений столбца fiction
. На каждом уровне иерархии добавляется партиция/сабпартиция по умолчанию.
CREATE TABLE sales
(id INT,
date DATE,
fiction CHAR(1),
region text)
DISTRIBUTED BY (id)
PARTITION BY RANGE (date)
SUBPARTITION BY LIST (region)
SUBPARTITION TEMPLATE (
SUBPARTITION rus VALUES ('rus'),
SUBPARTITION asia VALUES ('asia'),
SUBPARTITION europe VALUES ('europe'),
DEFAULT SUBPARTITION other_rg
)
SUBPARTITION BY LIST (fiction)
SUBPARTITION TEMPLATE (
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
)
(START(date '2022-01-01') INCLUSIVE
END(date '2022-04-01') EXCLUSIVE
EVERY(INTERVAL '1 month'),
DEFAULT PARTITION other_dt
);
Результат:
NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt" for table "sales" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_rus" for table "sales_1_prt_other_dt" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_rus_3_prt_fiction" for table "sales_1_prt_other_dt_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_rus_3_prt_non_fiction" for table "sales_1_prt_other_dt_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_rus_3_prt_other_tp" for table "sales_1_prt_other_dt_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_asia" for table "sales_1_prt_other_dt" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_asia_3_prt_fiction" for table "sales_1_prt_other_dt_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_asia_3_prt_non_fiction" for table "sales_1_prt_other_dt_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_asia_3_prt_other_tp" for table "sales_1_prt_other_dt_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_europe" for table "sales_1_prt_other_dt" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_europe_3_prt_fiction" for table "sales_1_prt_other_dt_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_europe_3_prt_non_fiction" for table "sales_1_prt_other_dt_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_europe_3_prt_other_tp" for table "sales_1_prt_other_dt_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_other_rg" for table "sales_1_prt_other_dt" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_other_rg_3_prt_fiction" for table "sales_1_prt_other_dt_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_other_rg_3_prt_non_fiction" for table "sales_1_prt_other_dt_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_other_dt_2_prt_other_rg_3_prt_other_tp" for table "sales_1_prt_other_dt_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_2" for table "sales" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_rus" for table "sales_1_prt_2" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_rus_3_prt_fiction" for table "sales_1_prt_2_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_rus_3_prt_non_fiction" for table "sales_1_prt_2_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_rus_3_prt_other_tp" for table "sales_1_prt_2_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_asia" for table "sales_1_prt_2" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_asia_3_prt_fiction" for table "sales_1_prt_2_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_asia_3_prt_non_fiction" for table "sales_1_prt_2_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_asia_3_prt_other_tp" for table "sales_1_prt_2_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_europe" for table "sales_1_prt_2" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_europe_3_prt_fiction" for table "sales_1_prt_2_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_europe_3_prt_non_fiction" for table "sales_1_prt_2_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_europe_3_prt_other_tp" for table "sales_1_prt_2_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_other_rg" for table "sales_1_prt_2" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_other_rg_3_prt_fiction" for table "sales_1_prt_2_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_other_rg_3_prt_non_fiction" for table "sales_1_prt_2_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_2_2_prt_other_rg_3_prt_other_tp" for table "sales_1_prt_2_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_3" for table "sales" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_rus" for table "sales_1_prt_3" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_rus_3_prt_fiction" for table "sales_1_prt_3_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_rus_3_prt_non_fiction" for table "sales_1_prt_3_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_rus_3_prt_other_tp" for table "sales_1_prt_3_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_asia" for table "sales_1_prt_3" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_asia_3_prt_fiction" for table "sales_1_prt_3_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_asia_3_prt_non_fiction" for table "sales_1_prt_3_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_asia_3_prt_other_tp" for table "sales_1_prt_3_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_europe" for table "sales_1_prt_3" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_europe_3_prt_fiction" for table "sales_1_prt_3_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_europe_3_prt_non_fiction" for table "sales_1_prt_3_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_europe_3_prt_other_tp" for table "sales_1_prt_3_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_other_rg" for table "sales_1_prt_3" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_other_rg_3_prt_fiction" for table "sales_1_prt_3_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_other_rg_3_prt_non_fiction" for table "sales_1_prt_3_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_3_2_prt_other_rg_3_prt_other_tp" for table "sales_1_prt_3_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_4" for table "sales" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_rus" for table "sales_1_prt_4" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_rus_3_prt_fiction" for table "sales_1_prt_4_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_rus_3_prt_non_fiction" for table "sales_1_prt_4_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_rus_3_prt_other_tp" for table "sales_1_prt_4_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_asia" for table "sales_1_prt_4" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_asia_3_prt_fiction" for table "sales_1_prt_4_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_asia_3_prt_non_fiction" for table "sales_1_prt_4_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_asia_3_prt_other_tp" for table "sales_1_prt_4_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_europe" for table "sales_1_prt_4" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_europe_3_prt_fiction" for table "sales_1_prt_4_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_europe_3_prt_non_fiction" for table "sales_1_prt_4_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_europe_3_prt_other_tp" for table "sales_1_prt_4_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_other_rg" for table "sales_1_prt_4" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_other_rg_3_prt_fiction" for table "sales_1_prt_4_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_other_rg_3_prt_non_fiction" for table "sales_1_prt_4_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_1_prt_4_2_prt_other_rg_3_prt_other_tp" for table "sales_1_prt_4_2_prt_other_rg" CREATE TABLE
Следующий пример показывает создание таблицы sales_manual
со структурой полностью идентичной таблице sales
, созданной выше — за исключением того, что сабпартиции определяются на каждом уровне индивидуально. Можно увидеть, что текст команды значительно увеличился, однако результат выполнения прежний.
CREATE TABLE sales_manual
(id INT,
date DATE,
fiction CHAR(1),
region text)
DISTRIBUTED BY (id)
PARTITION BY RANGE (date)
SUBPARTITION BY LIST (region)
SUBPARTITION BY LIST (fiction)
(PARTITION Jan2022 START(date '2022-01-01') INCLUSIVE
(
SUBPARTITION rus VALUES ('rus')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
SUBPARTITION asia VALUES ('asia')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
SUBPARTITION europe VALUES ('europe')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
DEFAULT SUBPARTITION other_rg
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
)
),
PARTITION Feb2022 START(date '2022-02-01') INCLUSIVE
(
SUBPARTITION rus VALUES ('rus')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
SUBPARTITION asia VALUES ('asia')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
SUBPARTITION europe VALUES ('europe')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
DEFAULT SUBPARTITION other_rg
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
)
),
PARTITION Mar2022 START(date '2022-03-01') INCLUSIVE
(
SUBPARTITION rus VALUES ('rus')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
SUBPARTITION asia VALUES ('asia')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
SUBPARTITION europe VALUES ('europe')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
DEFAULT SUBPARTITION other_rg
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
)
),
DEFAULT PARTITION other_dt
(
SUBPARTITION rus VALUES ('rus')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
SUBPARTITION asia VALUES ('asia')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
SUBPARTITION europe VALUES ('europe')
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
),
DEFAULT SUBPARTITION other_rg
(
SUBPARTITION fiction VALUES ('f'),
SUBPARTITION non_fiction VALUES ('n'),
DEFAULT SUBPARTITION other_tp
)
)
);
Результат:
NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt" for table "sales_manual" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_rus" for table "sales_manual_1_prt_other_dt" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_rus_3_prt_fiction" for table "sales_manual_1_prt_other_dt_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_rus_3_prt_non_fiction" for table "sales_manual_1_prt_other_dt_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_rus_3_prt_other_tp" for table "sales_manual_1_prt_other_dt_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_asia" for table "sales_manual_1_prt_other_dt" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_asia_3_prt_fiction" for table "sales_manual_1_prt_other_dt_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_asia_3_prt_non_fiction" for table "sales_manual_1_prt_other_dt_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_asia_3_prt_other_tp" for table "sales_manual_1_prt_other_dt_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_europe" for table "sales_manual_1_prt_other_dt" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_europe_3_prt_fiction" for table "sales_manual_1_prt_other_dt_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_europe_3_prt_non_fiction" for table "sales_manual_1_prt_other_dt_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_europe_3_prt_other_tp" for table "sales_manual_1_prt_other_dt_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_other_rg" for table "sales_manual_1_prt_other_dt" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_other_rg_3_prt_fiction" for table "sales_manual_1_prt_other_dt_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_other_rg_3_prt_non_fiction" for table "sales_manual_1_prt_other_dt_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_other_dt_2_prt_other_rg_3_prt_other_tp" for table "sales_manual_1_prt_other_dt_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022" for table "sales_manual" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_rus" for table "sales_manual_1_prt_jan2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_rus_3_prt_fiction" for table "sales_manual_1_prt_jan2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_rus_3_prt_non_fiction" for table "sales_manual_1_prt_jan2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_rus_3_prt_other_tp" for table "sales_manual_1_prt_jan2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_asia" for table "sales_manual_1_prt_jan2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction" for table "sales_manual_1_prt_jan2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_asia_3_prt_non_fiction" for table "sales_manual_1_prt_jan2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_asia_3_prt_other_tp" for table "sales_manual_1_prt_jan2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_europe" for table "sales_manual_1_prt_jan2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_europe_3_prt_fiction" for table "sales_manual_1_prt_jan2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_europe_3_prt_non_fiction" for table "sales_manual_1_prt_jan2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_europe_3_prt_other_tp" for table "sales_manual_1_prt_jan2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_other_rg" for table "sales_manual_1_prt_jan2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_other_rg_3_prt_fiction" for table "sales_manual_1_prt_jan2022_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_other_rg_3_prt_non_fiction" for table "sales_manual_1_prt_jan2022_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_jan2022_2_prt_other_rg_3_prt_other_tp" for table "sales_manual_1_prt_jan2022_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022" for table "sales_manual" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_rus" for table "sales_manual_1_prt_feb2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_rus_3_prt_fiction" for table "sales_manual_1_prt_feb2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_rus_3_prt_non_fiction" for table "sales_manual_1_prt_feb2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_rus_3_prt_other_tp" for table "sales_manual_1_prt_feb2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_asia" for table "sales_manual_1_prt_feb2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_asia_3_prt_fiction" for table "sales_manual_1_prt_feb2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_asia_3_prt_non_fiction" for table "sales_manual_1_prt_feb2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_asia_3_prt_other_tp" for table "sales_manual_1_prt_feb2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_europe" for table "sales_manual_1_prt_feb2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_europe_3_prt_fiction" for table "sales_manual_1_prt_feb2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_europe_3_prt_non_fiction" for table "sales_manual_1_prt_feb2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_europe_3_prt_other_tp" for table "sales_manual_1_prt_feb2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_other_rg" for table "sales_manual_1_prt_feb2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_other_rg_3_prt_fiction" for table "sales_manual_1_prt_feb2022_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_other_rg_3_prt_non_fiction" for table "sales_manual_1_prt_feb2022_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_feb2022_2_prt_other_rg_3_prt_other_tp" for table "sales_manual_1_prt_feb2022_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022" for table "sales_manual" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_rus" for table "sales_manual_1_prt_mar2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_rus_3_prt_fiction" for table "sales_manual_1_prt_mar2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_rus_3_prt_non_fiction" for table "sales_manual_1_prt_mar2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_rus_3_prt_other_tp" for table "sales_manual_1_prt_mar2022_2_prt_rus" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_asia" for table "sales_manual_1_prt_mar2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_asia_3_prt_fiction" for table "sales_manual_1_prt_mar2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_asia_3_prt_non_fiction" for table "sales_manual_1_prt_mar2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_asia_3_prt_other_tp" for table "sales_manual_1_prt_mar2022_2_prt_asia" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_europe" for table "sales_manual_1_prt_mar2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_europe_3_prt_fiction" for table "sales_manual_1_prt_mar2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_europe_3_prt_non_fiction" for table "sales_manual_1_prt_mar2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_europe_3_prt_other_tp" for table "sales_manual_1_prt_mar2022_2_prt_europe" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_other_rg" for table "sales_manual_1_prt_mar2022" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_other_rg_3_prt_fiction" for table "sales_manual_1_prt_mar2022_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_other_rg_3_prt_non_fiction" for table "sales_manual_1_prt_mar2022_2_prt_other_rg" NOTICE: CREATE TABLE will create partition "sales_manual_1_prt_mar2022_2_prt_other_rg_3_prt_other_tp" for table "sales_manual_1_prt_mar2022_2_prt_other_rg" CREATE TABLE
Внутренние детали партиционирования
Независимо от типа партиционирования, Greenplum создает верхнеуровневую (родительскую) таблицу с одним или несколькими уровнями дочерних таблиц. Между родительской и дочерними таблицами устанавливается отношение наследования, схожее по функциональности с INHERITS
в PostgreSQL. Если при использовании psql запустить команды \dt
или \dt+
для вывода списка отношений БД, можно убедиться, что все партиции и сабпартиции отобразятся в списке подобно обычным таблицам.
Родительские таблицы всегда пусты. Данные хранятся в дочерних партициях, при использовании многоуровневого партиционирования — в сабпартициях самого нижнего уровня (leaf-партициях).
Для проверки того, какие данные могут быть добавлены в партиции, Greenplum использует ограничения CHECK
. Строки, не удовлетворяющие спецификациям ни одной нижнеуровневой партиции, отклоняются, и загрузка данных завершается с ошибкой (при условии, что не определена партиция по умолчанию). Оптимизатор запросов также использует ограничения CHECK
для сканирования партиций, удовлетворяющих условиям предиката.
Чтобы добавить данные в партиционированную таблицу, необходимо использовать имя родительской таблицы, созданной с помощью команды CREATE TABLE
, либо указать полное имя нужной партиции нижнего уровня. В партиции промежуточных уровней добавлять данные не допускается.
Например, можно добавить данные в таблицу sales_manual
, созданную выше (см. Многоуровневое партиционирование (вручную)):
INSERT INTO sales_manual(id, date, fiction, region)
VALUES(1, date '2022-01-01', 'f', 'asia');
Также возможно добавить данные непосредственно в нижнеуровневую сабпартицию sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction
:
INSERT INTO sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction(id, date, fiction, region)
VALUES(2, date '2022-01-02', 'f', 'asia');
Однако нельзя добавить данные в партицию, не являющуюся нижнеуровневой (например, sales_manual_1_prt_jan2022
):
INSERT INTO sales_manual_1_prt_jan2022(id, date, fiction, region) VALUES(3, date '2022-01-03', 'f', 'asia');
Запрос возвращает ошибку:
ERROR: directly modifying intermediate part of a partitioned table is disallowed HINT: Modify either the root or a leaf partition instead.
Также нельзя добавить данные, не удовлетворяющие требованиям, которые определены в спецификации партиции:
INSERT INTO sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction(id, date, fiction, region)
VALUES(4, date '2022-01-02', 'n', 'asia');
Результат:
ERROR: trying to insert row into wrong partition (seg7 10.92.16.100:10007 pid=19273) DETAIL: Expected partition: sales_manual_1_prt_jan2022_2_prt_asia_3_prt_non_fiction, provided partition: sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction.
Для выбора данных из партиционированной таблицы можно обратиться как к родительской таблице, так и к дочерней сабпартиции, содержащей данные:
SELECT * FROM sales_manual;
SELECT * FROM sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction;
Оба запроса возвращают одинаковый результат:
id | date | fiction | region ----+------------+---------+-------- 1 | 2022-01-01 | f | asia 2 | 2022-01-02 | f | asia (2 rows)
Партиционирование существующей таблицы
Партиционировать таблицы можно только при их создании. Чтобы разделить на партиции существующую таблицу, необходимо создать новую партиционированную таблицу и загрузить в нее данные из исходной. Пример приведен ниже:
-
Создайте исходную таблицу без партиционирования:
CREATE TABLE genre (id INT, name TEXT NOT NULL, fiction CHAR(1) NOT NULL) DISTRIBUTED BY (id);
-
Создайте партиционированную таблицу с аналогичной структурой — с помощью выражения
LIKE
:CREATE TABLE genre_partitioned (LIKE genre) PARTITION BY LIST (fiction) (PARTITION fiction VALUES ('F'), PARTITION non_fiction VALUES ('N'), DEFAULT PARTITION other );
Результат:
NOTICE: table doesn't have 'DISTRIBUTED BY' clause, defaulting to distribution columns from LIKE table NOTICE: CREATE TABLE will create partition "genre_partitioned_1_prt_fiction" for table "genre_partitioned" NOTICE: CREATE TABLE will create partition "genre_partitioned_1_prt_non_fiction" for table "genre_partitioned" NOTICE: CREATE TABLE will create partition "genre_partitioned_1_prt_other" for table "genre_partitioned" CREATE TABLE
ВАЖНОПри создании таблицы с помощью выражения
LIKE
структура партиционирования не копируется. -
Загрузите данные из исходной таблицы в партиционированную:
INSERT INTO genre_partitioned SELECT * FROM genre;
-
Удалите исходную таблицу:
DROP TABLE genre;
-
Назначьте имя удаленной таблицы партиционированной таблице:
ALTER TABLE genre_partitioned RENAME TO genre;
-
Переопределите все необходимые разрешения для партиционированной таблицы. Например:
GRANT ALL PRIVILEGES ON genre TO gpadmin;
Просмотр партиционированных таблиц
Для просмотра существующих партиционированных таблиц в текущей БД можно использовать следующие способы:
-
Чтобы вывести структуру определенной таблицы, можно сделать выборку из системного представления pg_catalog.pg_partitions. Вместо
<schema_name>
следует использовать имя схемы, вместо<table_name>
— имя родительской таблицы.SELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = '<schema_name>' AND tablename = '<table_name>';
Эта команда возвращает следующие столбцы:
-
partitiontablename
— полное имя таблицы, используемое для обращения к партиции напрямую в DML-командах (таких какINSERT
,COPY
,SELECT
и так далее); -
partitionname
— имя партиции, которое назначается при создании и используется для обращения к партиции в командах ALTER TABLE; -
partitiontype
— тип партиционирования (range
илиlist
); -
partitionlevel
— уровень партиции (начиная с0
для партиций первого уровня); -
partitionrank
— ранг (rank) партиции в общем списке партиций на текущем уровне (начиная с1
). Заполняется только для партиций с типом range.
Можно также использовать столбец
partitionboundary
для вывода полных спецификаций партиций, указанных при создании.Результаты выполнения запроса для таблиц с разным типом партиционирования приведены ниже.
Таблица с типом партиционирования rangeSELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = 'public' AND tablename = 'book_order';
Результат:
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank ------------------------+---------------+---------------+----------------+--------------- book_order_1_prt_2 | | range | 0 | 1 book_order_1_prt_3 | | range | 0 | 2 book_order_1_prt_4 | | range | 0 | 3 book_order_1_prt_5 | | range | 0 | 4 book_order_1_prt_6 | | range | 0 | 5 book_order_1_prt_7 | | range | 0 | 6 book_order_1_prt_8 | | range | 0 | 7 book_order_1_prt_9 | | range | 0 | 8 book_order_1_prt_10 | | range | 0 | 9 book_order_1_prt_11 | | range | 0 | 10 book_order_1_prt_12 | | range | 0 | 11 book_order_1_prt_13 | | range | 0 | 12 book_order_1_prt_other | other | range | 0 | (13 rows)
Таблица с типом партиционирования listSELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = 'public' AND tablename = 'client';
Результат:
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank --------------------+---------------+---------------+----------------+--------------- client_1_prt_girls | girls | list | 0 | client_1_prt_boys | boys | list | 0 | client_1_prt_other | other | list | 0 | (3 rows)
Таблица с многоуровневым партиционированием (multi-level)SELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = 'public' AND tablename = 'sales' ORDER BY partitiontablename;
Результат:
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank -------------------------------------------------------+---------------+---------------+----------------+--------------- sales_1_prt_2 | | range | 0 | 1 sales_1_prt_2_2_prt_asia | asia | list | 1 | sales_1_prt_2_2_prt_asia_3_prt_fiction | fiction | list | 2 | sales_1_prt_2_2_prt_asia_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_2_2_prt_asia_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_2_2_prt_europe | europe | list | 1 | sales_1_prt_2_2_prt_europe_3_prt_fiction | fiction | list | 2 | sales_1_prt_2_2_prt_europe_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_2_2_prt_europe_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_2_2_prt_other_rg | other_rg | list | 1 | sales_1_prt_2_2_prt_other_rg_3_prt_fiction | fiction | list | 2 | sales_1_prt_2_2_prt_other_rg_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_2_2_prt_other_rg_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_2_2_prt_rus | rus | list | 1 | sales_1_prt_2_2_prt_rus_3_prt_fiction | fiction | list | 2 | sales_1_prt_2_2_prt_rus_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_2_2_prt_rus_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_3 | | range | 0 | 2 sales_1_prt_3_2_prt_asia | asia | list | 1 | sales_1_prt_3_2_prt_asia_3_prt_fiction | fiction | list | 2 | sales_1_prt_3_2_prt_asia_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_3_2_prt_asia_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_3_2_prt_europe | europe | list | 1 | sales_1_prt_3_2_prt_europe_3_prt_fiction | fiction | list | 2 | sales_1_prt_3_2_prt_europe_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_3_2_prt_europe_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_3_2_prt_other_rg | other_rg | list | 1 | sales_1_prt_3_2_prt_other_rg_3_prt_fiction | fiction | list | 2 | sales_1_prt_3_2_prt_other_rg_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_3_2_prt_other_rg_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_3_2_prt_rus | rus | list | 1 | sales_1_prt_3_2_prt_rus_3_prt_fiction | fiction | list | 2 | sales_1_prt_3_2_prt_rus_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_3_2_prt_rus_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_4 | | range | 0 | 3 sales_1_prt_4_2_prt_asia | asia | list | 1 | sales_1_prt_4_2_prt_asia_3_prt_fiction | fiction | list | 2 | sales_1_prt_4_2_prt_asia_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_4_2_prt_asia_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_4_2_prt_europe | europe | list | 1 | sales_1_prt_4_2_prt_europe_3_prt_fiction | fiction | list | 2 | sales_1_prt_4_2_prt_europe_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_4_2_prt_europe_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_4_2_prt_other_rg | other_rg | list | 1 | sales_1_prt_4_2_prt_other_rg_3_prt_fiction | fiction | list | 2 | sales_1_prt_4_2_prt_other_rg_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_4_2_prt_other_rg_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_4_2_prt_rus | rus | list | 1 | sales_1_prt_4_2_prt_rus_3_prt_fiction | fiction | list | 2 | sales_1_prt_4_2_prt_rus_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_4_2_prt_rus_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_other_dt | other_dt | range | 0 | sales_1_prt_other_dt_2_prt_asia | asia | list | 1 | sales_1_prt_other_dt_2_prt_asia_3_prt_fiction | fiction | list | 2 | sales_1_prt_other_dt_2_prt_asia_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_other_dt_2_prt_asia_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_other_dt_2_prt_europe | europe | list | 1 | sales_1_prt_other_dt_2_prt_europe_3_prt_fiction | fiction | list | 2 | sales_1_prt_other_dt_2_prt_europe_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_other_dt_2_prt_europe_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_other_dt_2_prt_other_rg | other_rg | list | 1 | sales_1_prt_other_dt_2_prt_other_rg_3_prt_fiction | fiction | list | 2 | sales_1_prt_other_dt_2_prt_other_rg_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_other_dt_2_prt_other_rg_3_prt_other_tp | other_tp | list | 2 | sales_1_prt_other_dt_2_prt_rus | rus | list | 1 | sales_1_prt_other_dt_2_prt_rus_3_prt_fiction | fiction | list | 2 | sales_1_prt_other_dt_2_prt_rus_3_prt_non_fiction | non_fiction | list | 2 | sales_1_prt_other_dt_2_prt_rus_3_prt_other_tp | other_tp | list | 2 | (68 rows)
-
-
Чтобы вывести все сабпартиции, созданные с помощью шаблона (subpartition template), можно сделать выборку из системного представления pg_catalog.pg_partition_templates.
SELECT schemaname, tablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partition_templates;
В дополнение к столбцам, описанным выше, этот запрос возвращает имя схемы
<schemaname>
и имя родительской таблицы<tablename>
. При необходимости можно выбрать данные только для определенной таблицы с использованием выраженияWHERE
.Результат запросаschemaname | tablename | partitionname | partitiontype | partitionlevel | partitionrank ------------+-----------+---------------+---------------+----------------+--------------- public | sales | rus | list | 1 | public | sales | asia | list | 1 | public | sales | europe | list | 1 | public | sales | other_rg | list | 1 | public | sales | fiction | list | 2 | public | sales | non_fiction | list | 2 | public | sales | other_tp | list | 2 | (7 rows)
-
Чтобы вывести все ключи партиционирования, можно обратиться к системному представлению pg_catalog.pg_partition_columns.
SELECT * FROM pg_catalog.pg_partition_columns;
Эта команда возвращает следующие столбцы:
-
schemaname
— имя схемы; -
tablename
— имя родительской таблицы; -
columnname
— имя столбца, используемого в качестве ключа партиционирования; -
partitionlevel
— уровень партиции (начиная с0
для партиций первого уровня); -
position_in_partition_key
— позиция столбца в составном ключе. Составные (multi-column) ключи партиционирования допускаются для партиций с типом list. По умолчанию,1
.
Результат запросаschemaname | tablename | columnname | partitionlevel | position_in_partition_key ------------+-------------------+-------------+----------------+--------------------------- public | book_order | order_date | 0 | 1 public | book | public_year | 0 | 1 public | book_order_manual | order_date | 0 | 1 public | book_manual | public_year | 0 | 1 public | client | gender | 0 | 1 public | sales | date | 0 | 1 public | sales | fiction | 2 | 1 public | sales | fiction | 2 | 1 public | sales | region | 1 | 1 public | sales | region | 1 | 1 public | sales_manual | date | 0 | 1 public | sales_manual | fiction | 2 | 1 public | sales_manual | region | 1 | 1 public | genre | fiction | 0 | 1 (14 rows)
-
-
Чтобы вывести партиционированные таблицы с перечислением всех уровней партиционирования, можно сделать выборку из таблицы системного каталога pg_catalog.pg_partition .
SELECT t2.relname, t1.parkind, t1.parlevel, t1.paristemplate FROM pg_partition t1 LEFT JOIN pg_class t2 ON t2.oid = t1.parrelid;
Вывод команды содержит следующие столбцы:
-
relname
— имя родительской таблицы; -
parkind
— тип партиционирования (r
для range,l
для list); -
parlevel
— уровень партиции (начиная с0
для партиций первого уровня); -
paristemplate
— признак того, является ли текущая строка определением шаблона (true
) или описанием непосредственно уровня в иерархии партиционирования (false
).
Результат запросаrelname | parkind | parlevel | paristemplate -------------------+---------+----------+--------------- book_order | r | 0 | f book | r | 0 | f book_order_manual | r | 0 | f book_manual | r | 0 | f client | l | 0 | f sales | l | 2 | f sales | l | 2 | t sales | l | 1 | f sales | l | 1 | t sales | r | 0 | f sales_manual | l | 2 | f sales_manual | l | 1 | f sales_manual | r | 0 | f genre | l | 0 | f (14 rows)
-
ПРИМЕЧАНИЕ
Последние два запроса возвращают по две строки для уровней |
Операции с партициями
Чтобы добавить новую партицию в партиционированную таблицу, необходимо использовать команду ALTER TABLE
с выражением ADD PARTITION
. Эту команду нельзя применять на одном уровне с партицией по умолчанию. Следующий пример показывает создание новой партиционированной таблицы и добавление нескольких партиций после создания:
-
Создайте двухуровневую партиционированную таблицу без партиций по умолчанию:
CREATE TABLE genre_stat (id SERIAL, jenre text NOT NULL, year INT NOT NULL, count INT NOT NULL) WITH (appendoptimized=true, orientation=row, compresstype=ZLIB, compresslevel=5) DISTRIBUTED BY(id) PARTITION BY RANGE (year) SUBPARTITION BY LIST (jenre) SUBPARTITION TEMPLATE ( SUBPARTITION poetry VALUES ('poetry'), SUBPARTITION fantasy VALUES ('fantasy'), SUBPARTITION detective VALUES ('detective') ) (START(2013) END(2015) EVERY(1));
Результат:
NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_1" for table "genre_stat" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_1_2_prt_poetry" for table "genre_stat_1_prt_1" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_1_2_prt_fantasy" for table "genre_stat_1_prt_1" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_1_2_prt_detective" for table "genre_stat_1_prt_1" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_2" for table "genre_stat" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_2_2_prt_poetry" for table "genre_stat_1_prt_2" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_2_2_prt_fantasy" for table "genre_stat_1_prt_2" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_2_2_prt_detective" for table "genre_stat_1_prt_2" CREATE TABLE
-
Добавьте новую партицию с помощью следующего запроса:
ALTER TABLE genre_stat ADD PARTITION START(2012) END(2013);
Результат приведен ниже. Поскольку при создании родительской таблицы использовался шаблон, новая партиция автоматически разделяется на сабпартиции в соответствии с ним. В противном случае необходимо было бы вручную описывать каждую сабпартицию для новой партиции.
NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_r188375637" for table "genre_stat" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_r188375637_2_prt_poetry" for table "genre_stat_1_prt_r188375637" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_r188375637_2_prt_fantasy" for table "genre_stat_1_prt_r188375637" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_r188375637_2_prt_detective" for table "genre_stat_1_prt_r188375637" ALTER TABLE
-
Возможно также добавление сабпартиций в существующие партиции. Для этого необходимо указать полный путь к новой сабпартиции при помощи выражений
ALTER PARTITION
— по одному выражению для каждого уровня партиционирования, предшествующего новой сабпартиции:ALTER TABLE genre_stat ALTER PARTITION FOR (RANK(1)) ADD PARTITION fantastic VALUES ('fantastic');
Результат:
NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_r188375637_2_prt_fantastic" for table "genre_stat_1_prt_r188375637" ALTER TABLE
-
Для просмотра обновленной структуры партиционированной таблицы используйте следующий запрос:
SELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = 'public' AND tablename = 'genre_stat' ORDER BY partitiontablename;
Результат:
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank ---------------------------------------------+---------------+---------------+----------------+--------------- genre_stat_1_prt_1 | | range | 0 | 2 genre_stat_1_prt_1_2_prt_detective | detective | list | 1 | genre_stat_1_prt_1_2_prt_fantasy | fantasy | list | 1 | genre_stat_1_prt_1_2_prt_poetry | poetry | list | 1 | genre_stat_1_prt_2 | | range | 0 | 3 genre_stat_1_prt_2_2_prt_detective | detective | list | 1 | genre_stat_1_prt_2_2_prt_fantasy | fantasy | list | 1 | genre_stat_1_prt_2_2_prt_poetry | poetry | list | 1 | genre_stat_1_prt_r188375637 | | range | 0 | 1 genre_stat_1_prt_r188375637_2_prt_detective | detective | list | 1 | genre_stat_1_prt_r188375637_2_prt_fantastic | fantastic | list | 1 | genre_stat_1_prt_r188375637_2_prt_fantasy | fantasy | list | 1 | genre_stat_1_prt_r188375637_2_prt_poetry | poetry | list | 1 | (13 rows)
ПРИМЕЧАНИЕ
|
Чтобы изменить имя партиции, необходимо использовать команду ALTER TABLE
с выражением RENAME PARTITION
. Следующий пример показывает переименование партиции с рангом 1
для родительской таблицы book
, созданной выше (см. Партиционирование на основе числовых диапазонов (автоматически)).
-
Проверьте текущее имя партиции:
SELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = 'public' AND tablename = 'book';
Результат приведен ниже. Партиция с рангом
1
имеет полное табличное имяbook_1_prt_2
, где2
— автоматичекси сгенерированный номер при создании:partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank --------------------+---------------+---------------+----------------+--------------- book_1_prt_2 | | range | 0 | 1 book_1_prt_3 | | range | 0 | 2 book_1_prt_4 | | range | 0 | 3 book_1_prt_5 | | range | 0 | 4 book_1_prt_6 | | range | 0 | 5 book_1_prt_7 | | range | 0 | 6 book_1_prt_8 | | range | 0 | 7 book_1_prt_9 | | range | 0 | 8 book_1_prt_10 | | range | 0 | 9 book_1_prt_11 | | range | 0 | 10 book_1_prt_other | other | range | 0 | (11 rows)
-
Переименуйте партицию, как указано ниже:
ALTER TABLE book RENAME PARTITION FOR(rank(1)) TO year2013;
Результат:
ALTER TABLE
-
Проверьте имя партиции повторно (используя запрос с шага 1). Имя партиции
partitionname
и имя соответствующей таблицыpartitiontablename
обновлены:partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank ---------------------+---------------+---------------+----------------+--------------- book_1_prt_year2013 | year2013 | range | 0 | 1 book_1_prt_3 | | range | 0 | 2 book_1_prt_4 | | range | 0 | 3 book_1_prt_5 | | range | 0 | 4 book_1_prt_6 | | range | 0 | 5 book_1_prt_7 | | range | 0 | 6 book_1_prt_8 | | range | 0 | 7 book_1_prt_9 | | range | 0 | 8 book_1_prt_10 | | range | 0 | 9 book_1_prt_11 | | range | 0 | 10 book_1_prt_other | other | range | 0 | (11 rows)
Обратите внимание, что изменения в имени родительской таблицы также распространяются на именя дочерних партиций. Например, следующая команда переименовывает таблицу book
в magazine
:
ALTER TABLE book RENAME TO magazine;
Изменения будут применены ко всем дочерним партициям. Чтобы убедиться в этом, можно выполнить запрос:
SELECT
partitiontablename,
partitionname,
partitiontype,
partitionlevel,
partitionrank
FROM pg_catalog.pg_partitions
WHERE schemaname = 'public'
AND tablename = 'magazine';
Результат:
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank -------------------------+---------------+---------------+----------------+--------------- magazine_1_prt_year2013 | year2013 | range | 0 | 1 magazine_1_prt_3 | | range | 0 | 2 magazine_1_prt_4 | | range | 0 | 3 magazine_1_prt_5 | | range | 0 | 4 magazine_1_prt_6 | | range | 0 | 5 magazine_1_prt_7 | | range | 0 | 6 magazine_1_prt_8 | | range | 0 | 7 magazine_1_prt_9 | | range | 0 | 8 magazine_1_prt_10 | | range | 0 | 9 magazine_1_prt_11 | | range | 0 | 10 magazine_1_prt_other | other | range | 0 | (11 rows)
Чтобы добавить партицию по умолчанию в партиционированную таблицу, необходимо использовать команду ALTER TABLE
с выражением ADD DEFAULT PARTITION
. Следующий пример показывает добавление партиции по умолчанию в таблицу genre_stat
, созданную выше (см. Добавление новой партиции):
-
Добавьте партицию по умолчанию на первом уровне:
ALTER TABLE genre_stat ADD DEFAULT PARTITION other;
Результат приведен ниже. Все сабпартиции создаются автоматически в соответствии с шаблоном, использованным при создании таблицы.
NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_other" for table "genre_stat" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_other_2_prt_poetry" for table "genre_stat_1_prt_other" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_other_2_prt_fantasy" for table "genre_stat_1_prt_other" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_other_2_prt_detective" for table "genre_stat_1_prt_other" NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_other_2_prt_fantastic" for table "genre_stat_1_prt_other" ALTER TABLE
-
Возможно также добавление партиций по умолчанию на других уровнях иерархии. Для этого необходимо указать полный путь к новой партиции при помощи выражений
ALTER PARTITION
— по одному выражению для каждого уровня партиционирования, предшествующего партиции по умолчанию. Следующий запрос создает партицию по умолчанию на втором уровне иерархии:ALTER TABLE genre_stat ALTER PARTITION FOR (RANK(1)) ADD DEFAULT PARTITION other;
Результат:
NOTICE: CREATE TABLE will create partition "genre_stat_1_prt_r188375637_2_prt_other" for table "genre_stat_1_prt_r188375637" ALTER TABLE
-
Для просмотра обновленной структуры партиционированной таблицы выполните запрос:
SELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = 'public' AND tablename = 'genre_stat' ORDER BY partitiontablename;
Результат:
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank ---------------------------------------------+---------------+---------------+----------------+--------------- genre_stat_1_prt_1 | | range | 0 | 2 genre_stat_1_prt_1_2_prt_detective | detective | list | 1 | genre_stat_1_prt_1_2_prt_fantasy | fantasy | list | 1 | genre_stat_1_prt_1_2_prt_poetry | poetry | list | 1 | genre_stat_1_prt_2 | | range | 0 | 3 genre_stat_1_prt_2_2_prt_detective | detective | list | 1 | genre_stat_1_prt_2_2_prt_fantasy | fantasy | list | 1 | genre_stat_1_prt_2_2_prt_poetry | poetry | list | 1 | genre_stat_1_prt_other | other | range | 0 | genre_stat_1_prt_other_2_prt_detective | detective | list | 1 | genre_stat_1_prt_other_2_prt_fantastic | fantastic | list | 1 | genre_stat_1_prt_other_2_prt_fantasy | fantasy | list | 1 | genre_stat_1_prt_other_2_prt_poetry | poetry | list | 1 | genre_stat_1_prt_r188375637 | | range | 0 | 1 genre_stat_1_prt_r188375637_2_prt_detective | detective | list | 1 | genre_stat_1_prt_r188375637_2_prt_fantastic | fantastic | list | 1 | genre_stat_1_prt_r188375637_2_prt_fantasy | fantasy | list | 1 | genre_stat_1_prt_r188375637_2_prt_other | other | list | 1 | genre_stat_1_prt_r188375637_2_prt_poetry | poetry | list | 1 | (19 rows)
Для разделения партиции на две необходимо использовать команду ALTER TABLE
с выражением SPLIT PARTITION
. Следующий пример показывает разделение партиций в родительской таблице book_order
, созданной выше (см. Партиционирование на основе диапазонов дат (автоматически)):
-
Разделите партицию, хранящую данные за январь 2022 года:
ALTER TABLE book_order SPLIT PARTITION FOR ('2022-01-01') AT ('2022-01-16') INTO (PARTITION jan1to15, PARTITION jan16to31);
Результат приведен ниже. Значение, на основе которого производится деление (
2022-01-16
), попадает во вторую партицию. Поэтому первая партиция будет хранить данные с 1 по 15 января 2022 года, вторая партиция — с 16 по 31 января 2022 года.NOTICE: CREATE TABLE will create partition "book_order_1_prt_jan1to15" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_jan16to31" for table "book_order" ALTER TABLE
-
Операция split также применяется для добавления новых партиций на одном уровне с партициями по умолчанию. Попробуйте добавить новую партицию (для хранения данных за декабрь 2021 года) в таблицу
book_order
:ALTER TABLE book_order ADD PARTITION START ('2021-12-01') END ('2022-01-01');
Команда возвращает следующую ошибку:
ERROR: cannot add RANGE partition to relation "book_order" with DEFAULT partition "other" HINT: need to SPLIT partition "other"
-
Разделите партицию по умолчанию
other
с помощью следующей команды:ALTER TABLE book_order SPLIT DEFAULT PARTITION START ('2021-12-01') END ('2022-01-01') INTO (PARTITION dec21, DEFAULT PARTITION);
Результат приведен ниже:
NOTICE: exchanged partition "other" of relation "book_order" with relation "pg_temp_61865" NOTICE: dropped partition "other" for relation "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_dec21" for table "book_order" NOTICE: CREATE TABLE will create partition "book_order_1_prt_other" for table "book_order" ALTER TABLE
-
Для просмотра обновленной структуры партиционированной таблицы используйте следующий запрос:
SELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = 'public' AND tablename = 'book_order';
Результат:
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank ----------------------------+---------------+---------------+----------------+--------------- book_order_1_prt_dec21 | dec21 | range | 0 | 1 book_order_1_prt_jan1to15 | jan1to15 | range | 0 | 2 book_order_1_prt_jan16to31 | jan16to31 | range | 0 | 3 book_order_1_prt_3 | | range | 0 | 4 book_order_1_prt_4 | | range | 0 | 5 book_order_1_prt_5 | | range | 0 | 6 book_order_1_prt_6 | | range | 0 | 7 book_order_1_prt_7 | | range | 0 | 8 book_order_1_prt_8 | | range | 0 | 9 book_order_1_prt_9 | | range | 0 | 10 book_order_1_prt_10 | | range | 0 | 11 book_order_1_prt_11 | | range | 0 | 12 book_order_1_prt_12 | | range | 0 | 13 book_order_1_prt_13 | | range | 0 | 14 book_order_1_prt_other | other | range | 0 | (15 rows)
ПРИМЕЧАНИЕ
|
Операция обмена (exchange) позволяет заменять партицию на таблицу с аналогичной структурой. Эту таблицу принято называть staging-таблицей. После применения операции staging-таблица содержит данные партиции, а партиция — данные staging-таблицы. Этот функционал особенно полезен для загрузки данных, поскольку вставка данных непосредственно в сами партиции не рекомендуется в силу своей неэффективности. Обмен партиции также позволяет изменять тип хранения данных в существующих партициях.
Чтобы выполнить обмен партиции, необходимо использовать команду ALTER TABLE
с выражением EXCHANGE PARTITION
.
Следующий пример показывает обмен партиции для таблицы book_order_manual
, созданной выше (см. Партиционирование на основе диапазонов дат (вручную)):
-
Просмотрите родительскую таблицу вместе со всеми партициями, используя команду psql
\dt+
:\dt+ book_order_manual*
Результат:
List of relations Schema | Name | Type | Owner | Storage | Size | Description --------+-------------------------------+-------+---------+-------------+--------+------------- public | book_order_manual | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_apr22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_aug22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_dec22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_feb22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_jan22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_jul22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_jun22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_mar22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_may22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_nov22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_oct22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_other | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_sep22 | table | gpadmin | append only | 544 kB | (14 rows)
-
Убедитесь, что партиция
book_order_manual_1_prt_dec22
не содержит данных:SELECT * FROM book_order_manual_1_prt_dec22;
Результат:
id | book_id | client_id | book_count | order_date ----+---------+-----------+------------+------------ (0 rows)
-
Создайте новую таблицу с той же структурой, что у партиционированной таблицы
book_order_manual
. Выберите другой тип хранения данных (heap):CREATE TABLE dec22 (LIKE book_order_manual) WITH (appendoptimized=false);
Результат:
NOTICE: table doesn't have 'DISTRIBUTED BY' clause, defaulting to distribution columns from LIKE table CREATE TABLE
-
Добавьте данные в новую таблицу:
INSERT INTO dec22(id, book_id, client_id, book_count, order_date) VALUES(1, 1, 1, 1, '2022-12-01');
Результат:
INSERT 0 1
-
Замените партицию
book_order_manual_1_prt_dec22
новой таблицей. Используйте выражениеWITH VALIDATION
для включения проверки того, что данные в таблице отвечают требованиям из спецификации партиции. ВыражениеWITHOUT VALIDATION
может быть использовано для отключения такой проверки:ALTER TABLE book_order_manual EXCHANGE PARTITION FOR (DATE '2022-12-01') WITH TABLE dec22 WITH VALIDATION;
Результат:
NOTICE: exchanged partition "dec22" of relation "book_order_manual" with relation "dec22" ALTER TABLE
-
Проверьте, что партиция содержит данные (используя запрос с шага 2):
adb=# SELECT * FROM book_order_manual_1_prt_dec22; id | book_id | client_id | book_count | order_date ----+---------+-----------+------------+------------ 1 | 1 | 1 | 1 | 2022-12-01 (1 row)
-
Убедитесь, что тип хранения данных в партиции также изменился (используя psql-команду с шага 1):
adb=# \dt+ book_order_manual* List of relations Schema | Name | Type | Owner | Storage | Size | Description --------+-------------------------------+-------+---------+-------------+--------+------------- public | book_order_manual | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_apr22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_aug22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_dec22 | table | gpadmin | heap | 32 kB | public | book_order_manual_1_prt_feb22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_jan22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_jul22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_jun22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_mar22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_may22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_nov22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_oct22 | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_other | table | gpadmin | append only | 544 kB | public | book_order_manual_1_prt_sep22 | table | gpadmin | append only | 544 kB | (14 rows)
Возможность обмена для партиций по умолчанию (default partitions) изначально отключена. Но это поведение системы можно изменить с помощью установки серверного конфигурационного параметра gp_enable_exchange_default_partition в значение on
. Это позволит использовать выражение EXCHANGE DEFAULT PARTITION
в команде ALTER TABLE
. При обмене партиций по умолчанию важно проверять, чтобы данные в staging-таблице были валидны исключительно для партиции по умолчанию и не подходили под требования какой-либо из других партиций.
ПРИМЕЧАНИЕ
|
Чтобы удалить все данные из партиции без удаления самой партиции, необходимо использовать команду ALTER TABLE
с выражением TRUNCATE PARTITION
. Следующий пример показывает удаление данных из партиции sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction
, которые были добавлены выше:
-
Проверьте наличие данных в партиции:
SELECT * FROM sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction;
Результат:
id | date | fiction | region ----+------------+---------+-------- 2 | 2022-01-02 | f | asia 1 | 2022-01-01 | f | asia (2 rows)
-
Удалите данные из партиции. Обратите внимание, что для таблиц с многоуровневым партиционированием необходимо указывать полный путь к дочерней партиции, используя выражения
ALTER PARTITION
для описания каждого уровня партиционирования, предшествующего искомой партиции:ALTER TABLE sales_manual ALTER PARTITION jan2022 ALTER PARTITION asia TRUNCATE PARTITION fiction;
Результат:
NOTICE: truncated partition "fiction" for partition "asia" of partition "jan2022" of relation "sales_manual" ALTER TABLE
-
Убедитесь, что партиция более не содержит данных (используя запрос с шага 1):
adb=# SELECT * FROM sales_manual_1_prt_jan2022_2_prt_asia_3_prt_fiction; id | date | fiction | region ----+------+---------+-------- (0 rows)
ПРИМЕЧАНИЕ
При удалении данных из партиции, имеющей сабпартиции, данные из последних также автоматически удаляются.
|
Чтобы удалить партицию, необходимо использовать команду ALTER TABLE
с выражением DROP PARTITION
. Следующий пример показывает удаление партиции Year2013
из таблицы book_manual
, созданной выше (см. Партиционирование на основе числовых диапазонов (вручную)):
-
Проверьте существование партиции:
SELECT partitiontablename, partitionname, partitiontype, partitionlevel, partitionrank FROM pg_catalog.pg_partitions WHERE schemaname = 'public' AND tablename = 'book_manual';
Результат:
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank ----------------------------+---------------+---------------+----------------+--------------- book_manual_1_prt_year2013 | year2013 | range | 0 | 1 book_manual_1_prt_year2014 | year2014 | range | 0 | 2 book_manual_1_prt_year2015 | year2015 | range | 0 | 3 book_manual_1_prt_year2016 | year2016 | range | 0 | 4 book_manual_1_prt_year2017 | year2017 | range | 0 | 5 book_manual_1_prt_year2018 | year2018 | range | 0 | 6 book_manual_1_prt_year2019 | year2019 | range | 0 | 7 book_manual_1_prt_year2020 | year2020 | range | 0 | 8 book_manual_1_prt_year2021 | year2021 | range | 0 | 9 book_manual_1_prt_year2022 | year2022 | range | 0 | 10 book_manual_1_prt_other | other | range | 0 | (11 rows)
-
Удалите партицию:
ALTER TABLE book_manual DROP PARTITION year2013;
Результат:
ALTER TABLE
-
Убедитесь, что партиция более не существует (используя запрос с шага 1):
partitiontablename | partitionname | partitiontype | partitionlevel | partitionrank ----------------------------+---------------+---------------+----------------+--------------- book_manual_1_prt_year2014 | year2014 | range | 0 | 1 book_manual_1_prt_year2015 | year2015 | range | 0 | 2 book_manual_1_prt_year2016 | year2016 | range | 0 | 3 book_manual_1_prt_year2017 | year2017 | range | 0 | 4 book_manual_1_prt_year2018 | year2018 | range | 0 | 5 book_manual_1_prt_year2019 | year2019 | range | 0 | 6 book_manual_1_prt_year2020 | year2020 | range | 0 | 7 book_manual_1_prt_year2021 | year2021 | range | 0 | 8 book_manual_1_prt_year2022 | year2022 | range | 0 | 9 book_manual_1_prt_other | other | range | 0 | (10 rows)
ПРИМЕЧАНИЕ
|