Presto

Presto (и его форк Trino) — распределённый SQL-движок для интерактивных запросов по петабайтам данных: быстрые SELECT по HDFS, S3, БД и API одновременно.

Уровень: средний 17 разделов ⏱ 2–3 часа

1. Что такое Presto

Presto — не хранилище: он «приезжает» к данным через коннекторы. Запрос к нескольким источникам (HDFS + MySQL + Kafka) в одном SELECT — федеративные запросы.

Отличие от Hive (пакетные задачи) — интерактивность: ответы за секунды, а не минуты.

2. Архитектура

3. Установка

docker run -d --name trino -p 8080:8080 trinodb/trino
docker exec -it trino trino

Клиенты: trino CLI, JDBC, Python-клиент presto-python-client.

4. Каталоги и схемы

SHOW CATALOGS;          # hive, mysql, tpch, system...
SHOW SCHEMAS FROM hive;
USE hive.default;

SELECT count(*) FROM my_table;

Каталог соответствует коннектору: catalog.schema.table — полный адрес данных.

5. Коннекторы

Файл etc/catalog/mysql.properties:

connector.name=mysql
connection-url=jdbc:mysql://db-host:3306
connection-user=readonly
connection-password=secret

Добавил файл — перезагрузи Coordinator — и БД доступна как каталог.

6. Федеративный запрос

SELECT
    u.name,
    sum(o.total) AS spent
FROM mysql.shop.users u
JOIN hive.warehouse.orders o ON u.id = o.user_id
WHERE o.dt >= DATE '2026-01-01'
GROUP BY u.name
ORDER BY spent DESC;

Один запрос — данные из двух миров.

7. Типичные задачи

8. Производительность

Каждый JOIN перепланируется: совмещай ключи джойна как соли партиций, чтобы распределённый shuffle не «раздувался».

9. Экосистема

10. Партиции и формат хранения

Разбивай данные по датам: партиции ускоряют фильтры, потому что Presto не читает лишние файлы.

SELECT count(*) FROM logs
WHERE dt = DATE '2026-09-01';
-- при партиции dt=... читается один каталог-партиция
Слишком глубокая вложенность каталогов ухудшает планирование. Разделяй по 1–2 уровням, остальное — через индексируемый столбец.

11. Продвинутый SQL: оконные функции

Оконные функции считают значения в рамках группы, не сжимая строки — удобно для рангов и накоплений:

SELECT
  user_id,
  revenue,
  rank() OVER (ORDER BY revenue DESC) AS rnk,
  sum(revenue) OVER (PARTITION BY month) AS month_total
FROM sales;

Полезные приёмы:

UNNEST с CROSS JOIN превращает массив-список в плоские строки. Это частый шаблон в дашбордах.

12. Безопасность и аутентификация

Presto/Trino умеют работать с внешними источниками авторизации:

http-server.authentication.type=DELEGATED  # через прокси
http-server.authentication.type=PASSWORD   # LDAP / RADIUS
http-server.http.enabled=false             # только HTTPS
allow-all на продакшене означает, что любой, кто прошёл аутентификацию, читает все каталоги. Ограничивай доступ по схеме и каталогу.

13. Экосистема и инструменты

Presto/Trino хорошо встраивается в пайплайны:

trino://user@coordinator:8443/catalog/schema

Держи коннекторы и версию движка в одном документированном месте, а повторно используемые SQL — в version-контроле как dbt-модели или .sql-файлы.

Разделяй роли: аналитики читают через Presto, а тяжёлую обработку отдают Spark/Hive (курсы Apache Spark, Hive).

14. Аппроксимации и работа с огромными данными

На петабайтных выборках точные агрегаты дороги. Presto даёт аппроксимации — чуть менее точные, но в разы быстрее:

approx_distinct(user_id)                       -- HyperLogLog
approx_percentile(revenue, 0.95)               -- квантиль
approx_set(user_id) + merge                  -- склейка оценок по партициям
TABLE(system.query(user_id)) -- нет: для выборок используй TABLESAMPLE
SELECT * FROM logs TABLESAMPLE BERNOULLI (1);   -- 1% строк
Не используй аппроксимации там, где цена ошибки высока: финансовые итоги и аудит требуют точных count/sum по постраничным обходам.

15. EXPLAIN: читаем план запроса

Медленный запрос начинается с плана. EXPLAIN показывает дерево операторов, EXPLAIN ANALYZE добавляет реальные времена и оценки:

EXPLAIN ANALYZE
SELECT region, sum(revenue)
FROM hive.sales.events
WHERE dt >= DATE '2026-09-01'
GROUP BY region;
Симптом в планеДействие
TableScan читает все партициидобавь фильтр по партиционной колонке
Exchange с большим количеством строкпроверь ключи join/shuffle
MemoryExceeded на stageувеличь память worker или упрости query
Partial Aggregation без «final»распределённая агрегация не сжалась — смотри ключи
Сравнивай EXPLAIN до и после изменения: если число прочитанных строк не меняется, значит улучшение не «дошло» до плана.

16. Оркестрация запросов и тестирование SQL

Повторяемые SQL превращай в артефакты: модели dbt, задачи Airflow, файлы в git.

dbt/dbt_project.yml
models/analytics/mrr.sql  # select ... from hive... 
tests/assert_mrr_positive.sql  # assert count(*) > 0
Версионируй не только SQL, но и каталоги/коннекторы: документированный config.yaml — это «код» кластера.

17. Устранение неполадок: типовые симптомы

Два-три диагностируемых симптома закрывают большинство инцидентов:

СимптомПричинаРешение
Все запросы «замерли»Coordinator перегруженпроверь JVM, очередь запросов, убери «долгие» SELECT
Куски плана падают с OOMмало памяти workerquery.max-memory-per-node и распределённость shuffle
Данные «старые» даже после записикеш метаданных партицийrefresh materialized view / invalidate
CLI висит без выводазапрос слишком тяжёлый или тупит источникlimit, EXPLAIN, проверка коннектора
Заводи мониторинг самого кластера (см. Prometheus): время ответа, загрузка Queue, память — это индикаторы «до» жалоб пользователей.

18. Стратегии JOIN и их влияние на план

Trino выбирает способ соединения автоматически, но понимать его полезно: broadcast join копирует маленькую таблицу на каждый worker, partitioned join перераспределяет данные по ключу:

-- посмотреть выбранную стратегию
EXPLAIN (TYPE DISTRIBUTED)
SELECT * FROM orders o
JOIN customers c ON o.customer_id = c.id;
СтратегияУсловиеРиск
Broadcastправая таблица малапереполнение памяти при большой правой части
Partitionedобе таблицы большиесетевой shuffle по ключу
Cross joinквадратное произведениеобычно ошибка в модели
Если JOIN внезапно «упал по памяти» — посмотри размер правой части: после роста витрины broadcast перестал помещаться.

19. Lakehouse: таблицы Iceberg и Delta

Современные кластера читают не «сырьё файлов», а таблицы с метаданными: Apache Iceberg и Delta Lake дают транзакции и versioning поверх объектного хранилища:

-- создание Iceberg-таблицы через Trino
CREATE TABLE db.events_catalog (
  event_date DATE,
  user_id    BIGINT,
  event      VARCHAR
) WITH (
  format = 'PARQUET',
  partitioning = ARRAY['event_date']
);
Не смешивай «сырые» файлы и managed-таблицы в одном префиксе хранилища — при последующих миграциях патч фатально «потеряет» данные.

20. Память и сброс на диск (spill)

Пока данные помещаются в память worker-а — всё быстро. Когда нет — Trino либо падает с OOM, либо (с включённым спиллом) сбрасывает промежуточные данные на диск:

-- конфиг на воркере: помимо max-memory-per-node
spill-enabled=true
spill-path=/mnt/spool   -- быстрый локальный диск
Баланс один и тот же всюду: сначала фильтры и партиционирование — потом ресуждение о том, «влезет ли в память».

21. Мониторинг кластера

Даже оптимизированный запрос не поможет, если кластер перегружен. Собирай сигналы «до» жалоб пользователей:

МетрикаЧто сигнализирует
Running Queriesочередь растёт — координатор не справляется
Memory usage / nodeприближение к лимиту — риск OOM и спилла
CPU и IO по нодеперекос загрузки работников
Среднее время запросадеградация незаметна, но чувствуется
curl -s localhost:8081/v1/query?max_entries=5
-- посмотреть текущие и прошедшие запросы кластера
Интегрируй метрики с Prometheus и Grafana: дашборд «здоровья» кластера окупается при первом же инциденте.

Что дальше

Разведай данные в Presto, храни и обрабатывай в Spark/Hive, а метрики из Kafka и ClickHouse подключай коннекторами.

← Вернуться к курсам