Глава 30. Hive-секционирование

Postgres Pro AXE поддерживает секционирование аналитических таблиц при их создании. Секционирование повышает производительность запросов на чтение больших таблиц за счёт разделения данных на небольшие части, или секции, которыми проще управлять. Секции — это наборы Parquet-файлов, которые создаются на основе одного или нескольких столбцов таблицы в определённом порядке. У каждой таблицы есть хотя бы одна секция.

Пример 30.1.

Предположим, у таблицы есть целочисленный столбец column1 со значениями в диапазоне от 1 до 10. Допустим, вы используете критические с точки зрения производительности аналитические запросы, которые фильтруют данные по этому столбцу в предложении WHERE.

Такие аналитические запросы можно существенно ускорить, если хранить строки таблицы (или их значения RowID) сгрупированными по значениям column1. В этом случае, чтобы извлечь все строки с определённым значением, например column1=2, нет необходимости сканировать таблицу целиком — строки уже сгруппированы.


В Postgres Pro AXE OLAP-данные хранятся в Parquet-файлах, которые используются как единицы секционирования для аналитических таблиц. В каждом файле у каждой секции есть фиксированное значение. Обработчик запросов может сопоставить условие в предложении WHERE с метаданными файлов и пропустить ненужные файлы.

Решение использует технологию Hive-секционирования, которая разделяет аналитические таблицы на несколько Parquet-файлов на основе последовательности столбцов (ключей секции). Файлы секционированной таблицы хранятся в листьях дерева каталогов, где имена подкаталогов имеют формат столбец=значение. Например, s3://bucket/table/year=2024/month=01/data.parquet.

Пример 30.2.

Пример ниже показывает дерево каталогов для аналитической таблицы, секционированной по столбцам year и month. Каталог orders — корень дерева. Как правило, имя корневого каталога совпадает с именем таблицы, но его можно изменить.

  orders
  ├── year=2021
  │    ├── month=1
  │    │   ├── file1.parquet
  │    │   └── file2.parquet
  │    └── month=2
  │        └── file3.parquet
  └── year=2022
      ├── month=11
      │   ├── file4.parquet
      │   └── file5.parquet
      └── month=12
          └── file6.parquet

Вы можете секционировать таблицу-кучу напрямую по столбцам year и month:

  COPY orders TO 'orders' (FORMAT parquet, PARTITION_BY (year, month));

Первое orders — это имя таблицы-кучи, а второе orders — это имя корневого каталога в дереве. В предложении PARTITION_BY нельзя использовать выражения, однако их можно создавать динамически как дополнительные столбцы:

  COPY (SELECT *, year(timestamp) AS year, month(timestamp) AS month FROM services) TO 'test' (PARTITION_BY (year, month));

OLAP-данные можно читать из дерева каталогов с помощью флага hive_partitioning:

  SELECT * FROM read_parquet('orders/*/*/*.parquet', hive_partitioning = true);

Если используется этот флаг, значения столбцов считываются из соответствующих подкаталогов.

В этом дереве каталогов Postgres Pro AXE пропускает чтение Parquet-файлов, которые не требуются для результатов запроса. Рассмотрим следующую команду:

  SELECT * FROM read_parquet('orders/*/*/*.parquet', hive_partitioning = true) WHERE year = 2022 AND month = 11;

Она читает следующие Parquet-файлы:

  orders
  └── year=2022
      └── month=11
          ├── file4.parquet
          └── file5.parquet

Создание секции по столбцу с высокой кардинальностью (в крайнем случае — с атрибутом UNIQUE) приводит к созданию неоправданно большого числа Parquet-файлов (отдельный файл для каждого значения столбца), что снижает производительность запросов и может превысить ограничение СУБД на число файлов для секционированной таблицы. Даже при стандартной кардинальности столбца секционирование не улучшает производительность аналитических запросов, в которых нет фильтрации по этому столбцу.

Максимальное число Parquet-файлов, создаваемых в результате секционирования, — 10 000. Если этот порог превышается, хранимая процедура отменяется.

Postgres Pro AXE может одновременно записывать OLAP-данные не более чем в 100 Parquet-файлов.

Рекомендуемый размер секции: 100 МБ.