Важно понимать поведение рекурсии и наследования, чтобы получить правильную парадигму партицирования. Как и в предыдущей статье, в этой разбираемся с новыми командами в GreenPlum 7 и изменениями в легаси-командах.
Ключевое слово ONLY
Всегда можно указать ключевое слово ONLY
, если не предполагается рекурсия. Допустим, мы хотим изменить метод доступа к будущим разделам, но не хотим, чтобы он применялся к существующим. Можем сделать следующее:
-- Assuming partitioned table 'sales' and all
-- of its child partitions are heap tables.
ALTER TABLE ONLY sales SET ACCESS METHOD ao_row;
Для секционированной таблицы зададим подходящий способ доступа:
\d+ sales
Partitioned table "public.sales"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------------+-----------+----------+---------+---------+--------------+-------------
id | integer | | | | plain | |
date | date | | | | plain | |
amt | numeric(10,2) | | | | main | |
Partition key: RANGE (date)
Partitions: jan_sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01')
Distributed by: (id)
Access method: ao_row
При этом существующий дочерний раздел приложения не будет затронут:
\d+ jan_sales
Table "public.jan_sales"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------------+-----------+----------+---------+---------+--------------+-------------
id | integer | | | | plain | |
date | date | | | | plain | |
amt | numeric(10,2) | | | | main | |
Partition of: sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01')
Partition constraint: ((date IS NOT NULL) AND (date >= '2023-01-01'::date) AND (date < '2023-02-01'::date))
Distributed by: (id)
Access method: heap
GRANT ONLY|REVOKE ONLY
Также в Greenplum 7 можем указать ключевое слово ONLY
для GRANT/REVOKE
, которых нет в PostgreSQL. Обратите внимание, что исторически у Greenplum было такое поведение, при котором GRANT|REVOKE
в родительской секционированной таблице рекурсивно выполнялось в её дочерних разделах. Greenplum 7 придерживается такого же поведения, но добавляет опцию ONLY
, чтобы обеспечить гибкость, если вы не хотите выполнять рекурсию.
Простой пример использования:
-- Let's say at some point you want two roles with read permission
-- on our 'sale' partitioned table, but one for existing partitions
-- and another for future partitions.
-- 1. Grant only on the parent table for just future partitions.
GRANT SELECT ON ONLY sales TO role_that_can_read_only_future_partitions;
-- 2. W/o "ONLY", this will grant for all existing partitions.
-- Then, revoke only for parent to limit permission for future partitions.
GRANT SELECT ON sales TO roles_that_can_read_only_existing_partitions;
REVOKE SELECT ON ONLY sales FROM roles_that_can_read_only_existing_partitions
Создание новой дочерней таблицы
Как правило, при создании новой таблицы в качестве дочернего раздела наследуются все свойства родительской таблицы. Начнём с таблицы sales
:
CREATE TABLE sales (id int, date date, amt decimal(10,2))
USING ao_row
DISTRIBUTED BY (id)
PARTITION BY RANGE (date);
Можем использовать два типа синтаксиса для создания новой таблицы в качестве дочернего раздела:
-- Create child partition using the new Greenplum 7 syntax
CREATE TABLE jan_sales PARTITION OF sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01');
-- Create child partition using the legacy syntax
ALTER TABLE sales ADD PARTITION feb_sales START ('2023-02-01') END ('2023-03-01');
Оба дочерних раздела унаследуют метод доступа к родительской таблице, ориентированный на добавление строк (ao_row
):
\d+ sales
Partitioned table "public.sales"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------------+-----------+----------+---------+---------+--------------+-------------
id | integer | | | | plain | |
date | date | | | | plain | |
amt | numeric(10,2) | | | | main | |
Partition key: RANGE (date)
Partitions: jan_sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01'),
sales_1_prt_feb_sales FOR VALUES FROM ('2023-02-01') TO ('2023-03-01')
Distributed by: (id)
Access method: ao_row
\d+ jan_sales
Table "public.jan_sales"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------------+-----------+----------+---------+---------+--------------+-------------
id | integer | | | | plain | |
date | date | | | | plain | |
amt | numeric(10,2) | | | | main | |
Partition of: sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01')
Partition constraint: ((date IS NOT NULL) AND (date >= '2023-01-01'::date) AND (date < '2023-02-01'::date))
Compression Type: None
Compression Level: 0
Block Size: 32768
Checksum: t
Distributed by: (id)
Access method: ao_row
\d+ sales_1_prt_feb_sales
Table "public.sales_1_prt_feb_sales"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------------+-----------+----------+---------+---------+--------------+-------------
id | integer | | | | plain | |
date | date | | | | plain | |
amt | numeric(10,2) | | | | main | |
Partition of: sales FOR VALUES FROM ('2023-02-01') TO ('2023-03-01')
Partition constraint: ((date IS NOT NULL) AND (date >= '2023-02-01'::date) AND (date < '2023-03-01'::date))
Compression Type: None
Compression Level: 0
Block Size: 32768
Checksum: t
Distributed by: (id)
Access method: ao_row
SPLIT PARTITION
SPLIT PARTITION
— особенный кейс, когда новые дочерние разделы создаются из существующего дочернего раздела. В этом случае новые разделы будут наследовать не родительскую секционированную таблицу, а разделенную дочернюю. Предположим, по какой-то причине мы сделали так, чтобы раздел feb_sales
в нашем примере имел метод доступа, отличный от родительского:
ALTER TABLE sales_1_prt_feb_sales SET ACCESS METHOD ao_column;
Теперь разделим его на два новых раздела:
ALTER TABLE sales
SPLIT PARTITION feb_sales AT ('2023-02-15') INTO
(partition feb_first_half, partition feb_second_half);
Теперь новые разделы будут иметь метод доступа, отличный от родительского (обратите внимание, что исходный раздел feb_sales
исчез):
\d+ sales
Partitioned table "public.sales"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------------+-----------+----------+---------+---------+--------------+-------------
id | integer | | | | plain | |
date | date | | | | plain | |
amt | numeric(10,2) | | | | main | |
Partition key: RANGE (date)
Partitions: jan_sales FOR VALUES FROM ('2023-01-01') TO ('2023-02-01'),
sales_1_prt_feb_first_half FOR VALUES FROM ('2023-02-01') TO ('2023-02-15'),
sales_1_prt_feb_second_half FOR VALUES FROM ('2023-02-15') TO ('2023-03-01')
Distributed by: (id)
Access method: ao_row
\d+ sales_1_prt_feb_first_half
Table "public.sales_1_prt_feb_first_half"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Compression Type | Compression Level | Block Size | Description
--------+---------------+-----------+----------+---------+---------+--------------+------------------+-------------------+------------+-------------
id | integer | | | | plain | | none | 0 | 32768 |
date | date | | | | plain | | none | 0 | 32768 |
amt | numeric(10,2) | | | | main | | none | 0 | 32768 |
Partition of: sales FOR VALUES FROM ('2023-02-01') TO ('2023-02-15')
Partition constraint: ((date IS NOT NULL) AND (date >= '2023-02-01'::date) AND (date < '2023-02-15'::date))
Distributed by: (id)
Access method: ao_column
Options: blocksize=32768, compresslevel=0, compresstype=none, checksum=true
Это поведение наследования в SPLIT PARTITION
остаётся таким же, как и в Greenplum 6.
Присоединение существующей таблицы
Рассмотрим кейс, когда мы не создаём новую таблицу, а просто присоединяем существующую таблицу в качестве дочернего раздела. В этом случае исходные свойства таблицы сохраняются после того, как она становится дочерним разделом. Предположим, изначально у нас была таблица recent_sales
, которую мы продолжаем часто обновлять, и по умолчанию она использует heap
access-метод:
CREATE TABLE recent_sales (id int, date date, amt decimal(10,2));
\d+ recent_sales;
Table "public.recent_sales"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------------+-----------+----------+---------+---------+--------------+-------------
id | integer | | | | plain | |
date | date | | | | plain | |
amt | numeric(10,2) | | | | main | |
Distributed by: (id)
Access method: heap
Мы хотим присоединить эту таблицу к секционированной таблице sales
. После этого она сохранит свои исходные свойства, включая метод доступа:
ALTER TABLE sales ATTACH PARTITION recent_sales
FOR VALUES FROM ('2023-12-01') TO ('2030-12-31');
\d+ recent_sales
Table "public.recent_sales"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+---------------+-----------+----------+---------+---------+--------------+-------------
id | integer | | | | plain | |
date | date | | | | plain | |
amt | numeric(10,2) | | | | main | |
Partition of: sales FOR VALUES FROM ('2023-12-01') TO ('2030-12-31')
Partition constraint: ((date IS NOT NULL) AND (date >= '2023-12-01'::date) AND (date < '2030-12-31'::date))
Distributed by: (id)
Access method: heap
EXCHANGE PARTITION
Ещё один кейс — когда EXCHANGE PARTITION
прикрепляет существующую внешнюю таблицу к дочернему разделу. В Greenplum 7 есть несколько изменений, как теперь новый дочерний раздел наследует свойства таблицы.
Как упоминалось в предыдущей статье, EXCHANGE PARTITION
в Greenplum 7 состоит из DETACHPARTITION
и ATTACH PARTITION
. В результате EXCHANGE PARTITION
больше похож на ATTACH PARTITION
по поведению наследования. Вот подробный список:
Владелец таблицы:
EXCHANGE PARTITION
не требует, чтобы у будущей таблицы разделов был тот же владелец, что и у родительской таблицы.Индекс:
EXCHANGE PARTITION
не требует, чтобы будущий раздел имел тот же индекс, что и родительский. Команда создаст его, если он отсутствует.Ограничение таблицы:
EXCHANGE PARTITION
требует, чтобы у будущего раздела были все ограничения, которые есть у его родителя.
Заключение
В общем, большинство команд ALTER TABLE
и GRANT|REVOKE
будут возвращаться к своим дочерним разделам, если только не указано ключевое слово ONLY
. И будет ли наследоваться новый дочерний раздел или нет, зависит от того, создан он или присоединен. Если он создан, он будет наследовать от родителя, в противном случае он сохраняет свои собственные исходные свойства.