Партицирование в GreenPlum 7: рекурсия и наследование

от автора

Важно понимать поведение рекурсии и наследования, чтобы получить правильную парадигму партицирования. Как и в предыдущей статье, в этой разбираемся с новыми командами в 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

«DWH на основе GreenPlum»

Создание новой дочерней таблицы

Как правило, при создании новой таблицы в качестве дочернего раздела наследуются все свойства родительской таблицы. Начнём с таблицы 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. И будет ли наследоваться новый дочерний раздел или нет, зависит от того, создан он или присоединен. Если он создан, он будет наследовать от родителя, в противном случае он сохраняет свои собственные исходные свойства.

«DWH на основе GreenPlum»


ссылка на оригинал статьи https://habr.com/ru/articles/727076/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *