Learning Platform
Глоссарий Troubleshooting
Урок 07.02 · 22 мин
Начальный
olapcolumnarmppdenormalizationsnowflakebigqueryclickhouse

Что такое OLAP

OLAP — Online Analytical Processing. Это базы данных, обслуживающие аналитические запросы: агрегации по миллиардам строк, JOIN-ы огромных таблиц, отчёты, дэшборды, исследовательские запросы аналитиков. В противоположность OLTP, где главное — много мелких операций, OLAP оптимизирован под мало запросов, каждый из которых сканирует и обрабатывает большие объёмы.

Канонические примеры OLAP-систем 2026 года:

  • Snowflake — облачный DWH, market leader.
  • Google BigQuery — serverless DWH в GCP.
  • Amazon Redshift — DWH в AWS, исторически на базе ParAccel.
  • ClickHouse — open-source OLAP от Yandex, фокус на скорости.
  • Databricks SQL — lakehouse engine поверх Spark/Delta.
  • DuckDB — in-process OLAP, “SQLite для аналитики”.
  • Apache Druid / Pinot — real-time OLAP для дашбордов.

Все они построены вокруг тех же идей: колоночное хранение + параллельное выполнение + минимум индексов + денормализация.

Три кита OLAP

1. Колоночное хранение (columnar)

Мы разобрали это в модуле 5. В OLAP-системах данные физически хранятся по колонкам, что даёт:

  • Projection pushdown: читаем только нужные колонки (из 100 — реально 3-5).
  • Predicate pushdown: по min/max в блоках пропускаются неподходящие данные.
  • Компрессия 10-20x: однородные данные сжимаются великолепно.
  • Vector processing: CPU обрабатывает массив значений за такт через SIMD.

2. MPP — Massively Parallel Processing

OLAP-движки распараллеливают запрос на много машин и/или ядер. Запрос разбивается на стадии, каждая стадия выполняется параллельно множеством worker-ов.

-- Этот запрос на 100 млрд строк
SELECT country, SUM(amount) FROM orders GROUP BY country;

-- В MPP-движке выполняется так:
-- 1. Каждый worker сканирует свою часть данных
-- 2. Каждый делает локальную агрегацию по country
-- 3. Результаты shuffle-ятся между worker-ами по hash(country)
-- 4. Финальная агрегация
-- 5. Сбор результата

Snowflake под капотом — это распределённая система с разделёнными storage (S3) и compute (warehouses). Можно поднять virtual warehouse на 4, 16, 64 узла, и тот же запрос выполняется во столько же раз быстрее (до определённого предела, ограниченного законом Амдала).

ClickHouse использует MPP внутри одного сервера (через много ядер) и distributed tables между серверами. BigQuery — фундаментально serverless, ты не управляешь slot-ами явно, движок сам параллелит на тысячах CPU.

MPP: распараллеливание запроса

Запрос разбивается на стадии, каждая исполняется параллельно

Запрос пользователя приходит в координатор. Тот парсит, оптимизирует, генерирует план выполнения и распределяет работу
Worker 1: сканит свою часть данных (1/N от всего), фильтрует, делает локальную агрегацию. Работает в RAM, через несколько ядер CPU параллельно
Worker 2: то же на другой части. В Snowflake virtual warehouse это разные ноды, в ClickHouse — разные ядра или серверы
Worker N: ещё одна часть. В типичном production кластере 4-64 worker-ов работают параллельно, дробление по hash или range
Shuffle/exchange: промежуточные результаты пересылаются между worker-ами по ключу GROUP BY. После shuffle каждый worker имеет все данные по своим группам
Final aggregation: ещё одна стадия — финальная агрегация после shuffle. Coordinator собирает финальный результат и возвращает клиенту

3. Денормализация

В отличие от OLTP, в OLAP таблицы намеренно денормализованы. Зачем — три причины:

  1. Меньше JOIN-ов. На миллиардах строк JOIN — самая дорогая операция. Если можно избежать — нужно избегать.
  2. Локальность. Все данные одной строки рядом, не нужно гоняться за foreign key-ами.
  3. Колоночная компрессия отлично работает на широких таблицах. Денормализованная wide table в Parquet/ClickHouse занимает не сильно больше нормализованной.

Типичная dimensional model (модуль 8):

  • Один большой fact table с метриками (orders с amounts, customer_id, product_id, date).
  • Несколько dimension tables с контекстом (customers, products, dates).
  • Star schema — один уровень JOIN-ов.

Или ещё более экстремально — One Big Table (OBT): вообще без JOIN-ов, все поля включены в одну широкую таблицу. На ClickHouse это часто самый быстрый вариант.

Что НЕ нужно в OLAP

Минимум индексов

OLTP стоит на индексах. OLAP — почти без индексов. Причины:

  • Сканы всё равно колоночные и parallelизованные, B-tree lookup на 1 миллиард строк не выигрывает у parallel scan.
  • Индексы дороги в обслуживании при больших объёмах INSERT.
  • Predicate pushdown через columnar statistics заменяет грубое skipping.

Snowflake не позволяет создать индекс вообще (есть micro-partitions с automatic clustering). ClickHouse имеет sparse primary index — это не B-tree, это разреженная structure для skipping. BigQuery — то же, кластеризация по колонкам, не индексы.

Малое внимание к транзакциям

OLAP-системы поддерживают транзакции, но это редко используется. Типичный workload — batch loads: раз в час/день большой COPY INTO. Internal операции (CTAS, INSERT INTO … SELECT) транзакционные, но точечных UPDATE-ов почти нет.

Snowflake поддерживает ACID, но isolation — Snapshot Isolation, концептуально похожая на READ COMMITTED. Никакого SERIALIZABLE с блокировками, и это нормально — никто не делает 1000 параллельных UPDATE одной строки в OLAP.

Нет UPDATE/DELETE на горячем пути

ClickHouse исторически не поддерживал UPDATE/DELETE вообще (только append-only + delayed mutations). В 2022-2024 добавили lightweight DELETE и UPDATE, но в production советуют использовать через ReplacingMergeTree.

Snowflake/BigQuery поддерживают UPDATE/DELETE, но они дорогие — переписывается целая micro-partition. Никто не делает UPDATE WHERE id = X тысячу раз в секунду.

Что делает OLAP быстрым

Сложим всё в одной картине. Запрос:

SELECT country, COUNT(*), SUM(amount)
FROM orders
WHERE event_date BETWEEN '2026-01-01' AND '2026-01-31'
GROUP BY country
ORDER BY SUM(amount) DESC
LIMIT 10;

На 100 млрд строк OLTP (Postgres) — это часы. ClickHouse/Snowflake — секунды. Почему:

  1. Columnar storage: читаются только 3 колонки (country, amount, event_date) из 30-100.
  2. Partition pruning: данные партиционированы по дате, читается только январь 2026.
  3. Predicate pushdown: внутри партиций — skipping блоков по statistics.
  4. Compression: даже эти 3 колонки сжаты в 10x.
  5. Parallel scan: 16-64 worker сканят данные одновременно.
  6. Vectorized processing: CPU обрабатывает 1024 значения за один cycle через SIMD.
  7. Distributed aggregation: партиальные суммы делаются локально, shuffle минимизирован.

В сумме: вместо чтения 100 GB+ из disk-а — реально читается 100 MB, обрабатывается за секунды.

Реальные числа

Один типичный benchmark (TPC-H, 1 TB):

  • Postgres (OLTP): час+ на сложные TPC-H запросы.
  • Snowflake (medium warehouse): 5-30 секунд.
  • BigQuery: 3-15 секунд.
  • ClickHouse (4-node): 1-5 секунд.

На bigger workloads (10 TB+, реальные production данные с реальными сложностями) разница в 50-500x ставит вопрос архитектуры однозначно: для аналитики — OLAP, никаких компромиссов.

Денормализация: пример

Возьмём те же orders из прошлого урока. В OLTP-Postgres схема нормализованная:

-- Postgres OLTP схема
CREATE TABLE customers (customer_id BIGINT PRIMARY KEY, name TEXT, country TEXT, ...);
CREATE TABLE products (product_id BIGINT PRIMARY KEY, name TEXT, category TEXT, price NUMERIC);
CREATE TABLE orders (order_id BIGINT PRIMARY KEY, customer_id BIGINT, product_id BIGINT, qty INT, created_at TIMESTAMP);

Для аналитического запроса “продажи по странам и категориям” нужен JOIN трёх таблиц.

В OLAP-ClickHouse — flat OBT:

-- ClickHouse OBT схема
CREATE TABLE orders_flat (
  order_id UInt64,
  customer_id UInt64,
  customer_name String,
  customer_country LowCardinality(String),
  product_id UInt64,
  product_name String,
  product_category LowCardinality(String),
  product_price Decimal(10, 2),
  qty UInt32,
  amount Decimal(12, 2),
  created_at DateTime
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(created_at)
ORDER BY (created_at, customer_id);

Тот же запрос — без JOIN-ов, чистый scan. ClickHouse LowCardinality даёт автоматическое dictionary encoding для country и category — несколько байт на значение.

Ценой денормализации: при изменении имени клиента нужно обновить миллионы строк. В OLAP это допустимо, потому что:

  • Имя клиента меняется редко.
  • Обновление идёт батчем, не в real-time.
  • Данные в OLAP всё равно derived от OLTP — переэкспортируется из источника.

OLAP-системы по типам

Ландшафт OLAP-систем 2026

Cloud DWH, lakehouse, real-time OLAP, in-process

Cloud DWH
Snowflake, BigQuery, RedshiftCloud DWH: Snowflake, BigQuery, Redshift. Полностью managed, separated storage/compute, эластичное масштабирование. Дорого, но просто. Для большинства enterprise аналитики
Lakehouse
Databricks, Trino, AthenaLakehouse: Databricks SQL, Trino/Athena over Iceberg/Delta. Storage в open format (Parquet) на S3/GCS, compute поверх. Дешевле, гибче, более complex
Real-time OLAP
ClickHouse, Druid, PinotReal-time OLAP: ClickHouse, Druid, Pinot. Sub-second queries, real-time ingestion. Для user-facing dashboards, observability, ad-tech
In-process
DuckDB, MotherDuckIn-process: DuckDB, MotherDuck. SQLite-like, embedded в Python/notebook. Для аналитики до 100 GB на локальной машине или single-node cloud

Когда использовать каждый класс

  • До 100 GB, individual analyst -> DuckDB на ноутбуке. Бесплатно, мгновенно, никаких infra.
  • Enterprise data warehouse, любая команда -> Snowflake или BigQuery. Удобно, дорого, full-feature.
  • Огромные объёмы, готовы к operating overhead -> Lakehouse (Databricks или Trino over Iceberg).
  • Real-time дашборды для пользователей -> ClickHouse или Druid. Sub-second latency.
  • Ad-hoc на data lake -> Athena/Trino, serverless поверх Parquet.

Углубление в clickhouse-course, sql-fundamentals, и модуль 15 (cloud data platforms).

ClickHouse: real-time OLAP — как устроен и почему быстр Window functions: аналитические вычисления в SQL

Попробуй сам

  1. Установи DuckDB (pip install duckdb). Скачай NYC Taxi data (1 файл за месяц). Сравни:
    • Загрузка в Postgres + агрегационный запрос
    • DuckDB на Parquet + тот же запрос
  2. Создай Snowflake/BigQuery trial аккаунт. Загрузи open dataset (TPC-H). Запусти TPC-H query 1 на разных размерах warehouse.
  3. Развороти ClickHouse локально (Docker). Создай MergeTree таблицу с миллиардом строк. Замерь время GROUP BY запросов.
  4. Сравни планы выполнения одного запроса в Postgres и DuckDB через EXPLAIN. Найди ключевые различия (Seq Scan vs Vectorized, B-tree lookup vs Min-Max skipping).
Проверка знанийKnowledge check
Команда переезжает с Postgres на ClickHouse для аналитики. Junior data engineer спрашивает: 'Зачем нам в ClickHouse колонка customer_country дублируется в каждой строке orders — это же избыточно, нарушает 3NF, давайте сделаем как в Postgres через JOIN с customers'. Что объяснить?
ОтветAnswer
Денормализация в OLAP — это намеренный design choice, а не ошибка. Причины: 1) JOIN на миллиардах строк — самая дорогая операция, избегаем; 2) ClickHouse columnar + LowCardinality(String) хранит миллионы строк 'RU' как несколько байт через dictionary encoding — overhead практически нулевой; 3) sequential read одной wide-таблицы намного быстрее, чем JOIN двух с lookup-ами; 4) данные в OLAP — derived от OLTP, обновления идут батчем при перезагрузке, не точечные UPDATE-ы. Правило: 3NF для OLTP (write-optimized), денормализация для OLAP (read-optimized). Это не bug, это feature.

Проверьте понимание

Результат: 0 из 0
Аналитический
Вопрос 1 из 5. Запрос SELECT country, SUM(amount) FROM orders WHERE date >= '2026-01-01' GROUP BY country на 100 млрд строк. В Snowflake/ClickHouse это секунды, в Postgres — часы. Какие 3-4 механизма OLAP дают это ускорение?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4