ClickHouse и OLAP на собеседовании Data Engineer
Зачем DE спрашивают про ClickHouse и OLAP
ClickHouse — column-oriented OLAP-СУБД, созданная в Яндексе. Используется в Яндексе, Ozon, Avito, Wildberries, многих других — основной инструмент для real-time аналитики на больших объёмах. Типичная нагрузка: миллиарды строк, аналитические запросы, materialized views.
На собесе Data Engineer ClickHouse — частый блок в командах с большой data-стек. Уровень: junior — знает основы синтаксиса; middle — понимает MergeTree, partitioning; senior — спроектирует cluster с replication, ReplacingMergeTree для CDC.
Column-store vs row-store
Row-store (PostgreSQL, MySQL): данные хранятся построчно. Хорошо для OLTP — частые INSERT/UPDATE, поиск конкретной строки.
Column-store (ClickHouse, Snowflake, BigQuery): данные хранятся по колонкам. Хорошо для OLAP — агрегаты по колонкам, чтение преобладает.
Преимущества column-store:
- Compression. Однотипные данные сжимаются в 10×+
- Чтение только нужных колонок. SELECT col1, col2 не читает остальные
- SIMD-инструкции. Vectorized execution
Недостатки:
- Медленный point-lookup
- Не для OLTP
- INSERT по одной строке плохо — нужны batch
MergeTree и его варианты
MergeTree — основной engine ClickHouse. Особенности:
- Partitioning по дате/значению — куски данных разделены физически
- Sorting по primary key — данные внутри parts отсортированы
- Sparse index — индекс не на каждую строку, а каждые N (по default 8192)
- Merge — фоновое слияние малых parts в большие
Варианты:
- ReplicatedMergeTree — репликация через ZooKeeper/Keeper
- ReplacingMergeTree — дедупликация по primary key (последнее значение)
- SummingMergeTree — автоматическое суммирование при merge
- AggregatingMergeTree — кастомные агрегатные функции при merge
- CollapsingMergeTree — для CDC: pair record(sign=1) + cancel(sign=-1) = пусто
- VersionedCollapsingMergeTree — CollapsingMergeTree с version column
Partitioning
В ClickHouse partition — физически отдельный directory на диске. Обычно по toYYYYMM(date) или toDate(date).
Зачем:
- Pruning при запросах по дате — читать только нужные partitions
- TTL и удаление —
DROP PARTITIONмгновенный - Параллелизация — каждая partition обрабатывается отдельно
Размер partition: баланс. Слишком много мелких — overhead. Слишком мало больших — нет pruning.
Primary key и sorting
В ClickHouse PK ≠ unique key. PK — это sorting key: данные хранятся отсортированными по PK.
Хороший PK:
- Колонки, по которым часто фильтруют
- Низкая cardinality в первой колонке, увеличивая дальше
- Обычно:
(user_id, event_time)или(date, user_id)
Sparse index: ClickHouse не хранит индекс на каждую строку, а каждые N (granularity, default 8192). При SELECT с фильтром по PK — pruning блоков.
Materialized views
В ClickHouse MV — это insert trigger, не lazy refresh.
CREATE MATERIALIZED VIEW mv_daily_revenue
ENGINE = SummingMergeTree
PARTITION BY toYYYYMM(DATE)
ORDER BY DATE
AS SELECT toDate(event_time) AS DATE, sum(amount) AS revenue
FROM events
GROUP BY DATE;При INSERT в events, ClickHouse автоматически добавляет агрегаты в MV. Запросы к MV — мгновенные, потому что данные предагрегированы.
Use cases: real-time дашборды, готовые агрегаты для частых запросов.
ReplacingMergeTree для CDC
Когда source-data меняется (UPDATE/DELETE), ReplacingMergeTree даёт дедупликацию.
CREATE TABLE orders (
order_id Int64,
status String,
updated_at DateTime
)
ENGINE = ReplacingMergeTree(updated_at)
PARTITION BY toYYYYMM(updated_at)
ORDER BY order_id;При merge в одну partition с одним order_id — оставляется запись с max updated_at.
Важно: дедупликация только при merge (асинхронно). Для актуального результата нужно FINAL в запросе или OPTIMIZE TABLE FINAL. FINAL медленный — не для production.
Альтернатива: projection или materialized view с правильной агрегацией.
Distributed tables и кластеры
ClickHouse cluster = несколько shards, каждая shard = одна или несколько replicas.
Distributed table — виртуальная таблица, маршрутизирует запросы на правильные shards.
Sharding key определяет, в какой shard писать. По default — hash, можно настроить (по user_id, по дате).
Replication — через ZooKeeper/Keeper. ReplicatedMergeTree координирует.
Quorum writes — INSERT возвращается только когда минимум N реплик записали.
Типичные вопросы
«Чем ClickHouse отличается от PostgreSQL?»
Column-store vs row-store. ClickHouse — для OLAP (агрегаты на масштабе), PostgreSQL — для OLTP (транзакции). ClickHouse не поддерживает constraints, FKs, медленный для small lookup-ов.
«Почему запрос работает 30 секунд вместо 100мс?»
(1) Нет фильтра по PK — full scan. (2) Низкая cardinality в первой колонке PK. (3) Нет partition pruning. (4) Слишком много мелких parts. (5) Неправильный engine — для CDC нужен ReplacingMergeTree.
«Когда использовать ReplacingMergeTree и его trade-off-ы?»
Для CDC-данных, где есть updates. Trade-off: дедупликация асинхронная (при merge). Запрос без FINAL может вернуть дубликаты. С FINAL — медленнее.
«Что такое materialized view в ClickHouse?»
Триггер на INSERT в исходную таблицу. При вставке в source — данные автоматически добавляются в MV. Подходит для real-time агрегации, дашбордов.
«Как масштабировать ClickHouse?»
Vertically (больше RAM/CPU) или horizontally (sharding). Sharding ключ должен быть равномерно распределённым. Репликация — для high availability.
Частые ошибки
- Использовать ClickHouse для OLTP. Это OLAP. Для UPDATE/DELETE по одной строке — не подходит
- INSERT по одной строке. Batch минимум 1000+ строк, иначе много мелких parts → деградация
- Неправильный PK. Высокая cardinality в первой колонке → нет pruning
FINALв production.FINALмедленный. Для актуального состояния используй другие подходы- Игнорировать TTL. Без TTL таблица растёт бесконечно
FAQ
ClickHouse vs Snowflake?
Оба OLAP. ClickHouse — open-source, self-hosted или managed (Cloud), низкая latency. Snowflake — fully managed, fully serverless, дороже но проще в operations.
Нужно ли уметь администрировать?
Middle — нет, basic config достаточно. Senior — желательно понимать cluster setup, replication, backup.
Какие книги?
Документация ClickHouse — главная. «ClickHouse — High-Performance Analytics» (русскоязычные авторы) — полезная для углубления.
Сколько готовиться?
С нуля — 1-2 месяца с практикой. Уже работал — 2-3 недели.
Спрашивают ли low-level (на диске storage format)?
На senior — да. Понимать parts, sparse index, merge logic.