Гайды

Введение в ClickHouse для аналитики

MergeTree, PARTITION BY и ORDER BY, батч-вставки, типы данных, FORMAT и отличие OLAP от OLTP.

~12 мин чтения

Введение в ClickHouse для аналитики

ClickHouse — колоночная СУБД для OLAP: агрегации по большим объёмам, отчёты, логи, метрики. Строки хранятся колонками, сжатие сильное, векторизация запросов. Это не замена PostgreSQL для OLTP: вставки батчами, точечные UPDATE строки дороже.

Тонкая настройка сервера и запросов — в «Настройка и оптимизация ClickHouse». Официальная документация: clickhouse.com/docs.


1. Когда ClickHouse уместен

ПодходитМенее подходит
Витрины, BI, события, телеметрияЧастые точечные UPDATE одной строки
Скан миллиардов строк + GROUP BYМного мелких конкурирующих вставок по одной строке

2. Установка и клиент

bash
docker run -d --name clickhouse -p 8123:8123 -p 9000:9000 clickhouse/clickhouse-server
  • 8123 — HTTP.
  • 9000 — нативный протокол (clickhouse-client).
bash
docker exec -it clickhouse clickhouse-client -q "SELECT version()"

3. База, таблица, MergeTree

sql
CREATE DATABASE IF NOT EXISTS analytics;

CREATE TABLE analytics.events (
    event_date Date,
    event_time DateTime,
    user_id UInt64,
    event String,
    properties String
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(event_date)
ORDER BY (event_date, user_id, event_time);
  • MergeTree — основной движок; данные партами, фоном merge.
  • PARTITION BY — грубое разбиение (часто месяц); удобно DROP PARTITION для TTL.
  • ORDER BY — сортировка внутри парта и разреженный primary index по гранулам.

4. Вставка — батчи

Избегайте микро-вставок по одной строке: много мелких parts → нагрузка на merge.

sql
INSERT INTO analytics.events VALUES
    ('2025-04-01', '2025-04-01 10:00:00', 1, 'page_view', '{}'),
    ('2025-04-01', '2025-04-01 10:00:01', 2, 'click', '{"x":1}');

Файлы CSV/Parquet, INSERT SELECT, интеграции — см. документацию.

Через HTTP (8123) удобно грузить батчи: INSERT ... FORMAT JSONEachRow с телом запроса; для больших файлов — async_insert и параметры max_insert_block_size (см. доку вашей версии). Из приложений чаще используют нативный TCP (9000) или официальные клиенты — меньше оверхеда, чем у HTTP.


5. Чтение и агрегации

sql
SELECT
    toStartOfDay(event_time) AS day,
    event,
    count() AS cnt
FROM analytics.events
WHERE event_date >= '2025-04-01' AND event_date < '2025-05-01'
GROUP BY day, event
ORDER BY cnt DESC
LIMIT 20;

count() без аргумента оптимизирован.


6. Типы данных (обзор)

UInt* / Int*, String, FixedString(N), Date, DateTime, DateTime64, Decimal(P, S), Array(T), Nested, Tuple, JSON (зависит от версии). Не храните всё в String, если есть подходящий числовой/датовый тип.

Для низкой кардинальности (страна, тип события, код ошибки) используйте LowCardinality(String) — меньше RAM и быстрее группировки при умеренном числе уникальных значений.


7. ORDER BY и «первичный ключ»

В MergeTree ключ сортировки задаёт локальность и разреженный индекс; уникальность как в PostgreSQL не гарантируется — это не классический PK.


8. FORMAT

sql
SELECT * FROM analytics.events LIMIT 10 FORMAT JSONEachRow;

9. Материализованные представления

MaterializedView на MergeTree может складывать агрегаты в целевую таблицу при вставке в «сырьё» — типичный паттерн витрин (синтаксис зависит от версии).


10. Типичные ошибки

ОшибкаЭффект
Микро-батчиСлишком много parts
ORDER BY не совпадает с фильтрамиЛишнее сканирование
ClickHouse как key-valueНеверный инструмент
Удаление старого без партицийДорогие мутации вместо DROP PARTITION
Дедуп строк по ключу в витринеВместо «уникального индекса» смотрите ReplacingMergeTree / AggregatingMergeTree под задачу

Связанные материалы