Интенсив для Middle DWH Analyst: Trino, Greenplum и Data Vault 2.0

Интенсивный курс для подготовки к собеседованию на Middle DWH Analyst. Вы изучите архитектуру оптимизатора Trino [habr.com](https://habr.com/ru/companies/cedrusdata/articles/744934/), внутреннее устройство Greenplum и их сравнение [habr.com](https://habr.com/ru/companies/datasapience/articles/866862), а также разберете практические шаги проектирования Data Vault 2.0 [bigdataschool.ru](https://bigdataschool.ru/blog/news/greenplum/dwh-design-with-data-vault-example/) и его интеграцию с Greenplum [habr.com](https://habr.com/ru/companies/x5digital/articles/862384).

1. Trino под капотом: архитектура, фишки и оптимизатор SQL-запросов

Trino под капотом: архитектура, фишки и оптимизатор SQL-запросов

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

В отличие от классических реляционных баз данных, Trino не хранит данные локально. Он подключается к внешним источникам, извлекает нужную информацию, обрабатывает ее в оперативной памяти и возвращает результат пользователю. Это делает его идеальным инструментом для построения федеративных запросов и архитектуры Data Lakehouse.

Архитектура кластера: как распределяются задачи

Trino работает по принципу Massively Parallel Processing (MPP) — массивно-параллельной обработки. Запросы разбиваются на мелкие фрагменты, которые выполняются одновременно на множестве серверов. Кластер состоит из двух основных типов узлов: координатора и воркеров.

* Coordinator (Координатор) — мозг кластера. Он принимает SQL-запрос от клиента, парсит его, планирует выполнение и распределяет задачи. Координатор не занимается тяжелой обработкой данных, его цель — управление. * Worker (Воркер) — рабочая лошадка. Воркеры получают задачи от координатора, читают данные из источников, выполняют фильтрацию, агрегацию и объединение (Join), а затем передают промежуточные результаты друг другу или обратно координатору. * Connector (Коннектор) — плагин, который позволяет Trino общаться с конкретным источником данных (PostgreSQL, Hive, Kafka, S3). Коннектор транслирует внутренние команды Trino в понятный для источника формат.

> В среде симметричной многопроцессорной обработки (SMP) несколько процессоров совместно используют аппаратные ресурсы. В системах массивно-параллельной обработки (MPP) каждый узел имеет собственную память и вычислительные мощности, что позволяет масштабировать систему горизонтально практически без ограничений. > > IBM

Представим, что аналитику нужно свести данные о продажах из объектного хранилища S3 (100 ГБ) и справочник клиентов из PostgreSQL (5 ГБ). Координатор создаст план, по которому воркеры параллельно начнут читать куски файлов из S3 через коннектор Hive/Iceberg, а другие воркеры запросят данные из PostgreSQL. Вся магия объединения произойдет в оперативной памяти кластера Trino.

Оптимизатор запросов: от текста к физическому плану

Когда координатор получает SQL-запрос, текст проходит через парсер и превращается в Abstract Syntax Tree (AST) — абстрактное синтаксическое дерево. Затем AST преобразуется в реляционное дерево, над которым начинает работать оптимизатор.

Trino использует два подхода к оптимизации: Rule-based (на основе жестких правил) и Cost-based (на основе стоимости). Cost-Based Optimizer (CBO) оценивает различные варианты выполнения запроса, опираясь на статистику таблиц, которую предоставляют коннекторы.

Для выбора оптимального плана CBO анализирует:

  • Общее количество строк в таблице.
  • Долю NULL-значений в столбцах.
  • Количество уникальных значений (кардинальность).
  • Размер данных в байтах.
  • Опираясь на эти данные, оптимизатор принимает решение о типе объединения. Например, если размер одной из таблиц МБ, оптимизатор может выбрать Broadcast Join — скопировать эту маленькую таблицу на все воркеры. Если же обе таблицы огромны, будет использован Hash Join с перераспределением данных по хэш-ключу между всеми узлами.

    Предикатное проталкивание (Predicate Pushdown)

    Одной из важнейших фишек Trino является Predicate Pushdown — передача условий фильтрации на сторону источника данных. Вместо того чтобы вытягивать всю таблицу в память кластера и фильтровать ее там, Trino просит источник вернуть только нужные строки.

    В этом примере Trino не будет сканировать всю таблицу transactions. Через коннектор он отправит в PostgreSQL запрос, уже содержащий условие WHERE purchase_amount > 10000.

    Допустим, в таблице 50 миллионов строк общим объемом 10 ГБ. Транзакций с суммой больше 10 000 всего 5 000 строк (около 1 МБ). Благодаря предикатному проталкиванию по сети передастся только 1 МБ данных вместо 10 ГБ. Это колоссально снижает нагрузку на сеть и ускоряет выполнение запроса.

    Динамические фильтры (Dynamic Filtering)

    Аналитические запросы часто содержат операции Join между огромной таблицей фактов и маленькой таблицей измерений. Dynamic Filtering — это оптимизация, которая создает дополнительный предикат для одной стороны Join на основе данных, прочитанных из другой стороны.

    | Характеристика | Без динамических фильтров | С динамическими фильтрами | | :--- | :--- | :--- | | Чтение таблицы фактов | Полное сканирование (Full Scan) | Чтение только нужных партиций/строк | | Сетевой трафик | Максимальный | Минимальный | | Нагрузка на CPU воркеров | Высокая (фильтрация после чтения) | Низкая (данные отфильтрованы на источнике) |

    Представим запрос, который объединяет таблицу фактов sales (1 миллиард строк) и таблицу измерений stores (1000 строк), при этом мы ищем продажи только в одном конкретном магазине. Trino сначала быстро читает таблицу stores, находит ID нужного магазина, «на лету» формирует фильтр store_id = 5 и отправляет его воркерам, которые сканируют таблицу sales. Воркеры отбрасывают ненужные данные еще до того, как начнется ресурсоемкая операция объединения.

    Синтаксис и строгая типизация

    Trino строго следует стандарту ANSI SQL, но имеет важную отличительную черту — строгую типизацию. В отличие от некоторых СУБД (например, MySQL), которые могут неявно преобразовывать строку '123' в число 123, Trino выдаст ошибку. Аналитику необходимо явно использовать функцию CAST.

    Эта строгость защищает от скрытых ошибок производительности. Неявное приведение типов часто отключает использование индексов на стороне источника (блокирует Predicate Pushdown), что приводит к полному сканированию таблиц. Явное указание типов заставляет DWH-аналитика осознанно подходить к типам данных на этапе проектирования витрин.

    Понимание того, как Trino строит планы запросов, как работают коннекторы и почему важна статистика таблиц — это фундамент для Middle DWH Analyst. Эти знания позволяют писать запросы, которые выполняются за секунды, а не за часы, эффективно утилизируя вычислительные мощности кластера.