ClickHouse — колоночная СУБД для аналитики: она быстро считает агрегаты по миллиардам строк, но не предназначена для транзакционной нагрузки и точечных обновлений. Типичный сценарий — хранить события и метрики и отвечать на вопросы вида «сколько уникальных пользователей было вчера по региону». В статье разберём установку, модель данных на MergeTree, загрузку и обслуживание.

Где ClickHouse уместен, а где нет

База оптимизирована под последовательное чтение больших блоков и сжатие колонок. Запрос SELECT count() FROM events WHERE date = today() по сотням миллионов строк здесь — обычное дело. А вот UPDATE одной строки по первичному ключу — дорогая операция, которая выполняется асинхронной мутацией. Отсюда правило: ClickHouse ставят рядом с источником событий, а не вместо PostgreSQL для заказов.

  • Подходит: веб-аналитика, логи, метрики, финансовые отчёты, OLAP-витрины.
  • Не подходит: очереди, сессии, корзина интернет-магазина, частые построчные правки.
  • Хорошо сочетается: PostgreSQL для операционных данных плюс ClickHouse для аналитики.

Установка из официального репозитория

Для Debian и Ubuntu надёжнее официальный репозиторий: он даёт свежие пакеты и обновления безопасности. Команды выполняются от пользователя с sudo. Ключ и список источников нужно добавить один раз.

sudo apt-get install -y apt-transport-https ca-certificates curl gnupg
curl -fsSL https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key \
  | sudo gpg --dearmor -o /usr/share/keyrings/clickhouse-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb stable main" \
  | sudo tee /etc/apt/sources.list.d/clickhouse.list
sudo apt-get update
sudo apt-get install -y clickhouse-server clickhouse-client
sudo systemctl enable --now clickhouse-server

Первый запуск и клиент

После установки сервер слушает локальный порт и принимает подключения пользователя default без пароля. На сервере, доступном из сети, это недопустимо: сразу ограничьте прослушивание и задайте пароль.

clickhouse-client --query "SELECT version()"
clickhouse-client --query "SELECT name, value FROM system.settings WHERE name = 'max_memory_usage'"
sudo ss -ltnp | grep clickhouse

В /etc/clickhouse-server/config.xml оставьте в listen_host только 127.0.0.1 и ::1, если внешний доступ не нужен. Пользователей опишите в users.xml, задав каждому max_memory_usage.

Модель данных: MergeTree

Основной движок — MergeTree. Данные хранятся в партах, отсортированных по ключу ORDER BY, а партиции по PARTITION BY позволяют удалять старые данные целиком. Ключ сортировки — самый важный выбор: по нему строится разреженный первичный индекс, и он определяет, сколько гранул придётся прочитать.

CREATE DATABASE IF NOT EXISTS logs;

CREATE TABLE logs.events
(
    ts          DateTime,
    service     LowCardinality(String),
    level       LowCardinality(String),
    user_id     UInt64,
    message     String,
    duration_ms UInt32
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (service, ts, user_id)
TTL ts + INTERVAL 180 DAY
SETTINGS index_granularity = 8192;

LowCardinality(String) заметно экономит место на колонках с небольшим числом уникальных значений. Партиции по месяцу — разумный компромисс: слишком мелкое дробление создаёт тысячи партов, слишком крупное мешает удалять старое.

Загрузка данных

Вставляйте крупными батчами: одна вставка на строку убивает производительность. Для файлов используйте нативный формат или CSV с явной схемой. Проверьте, что порядок колонок совпадает.

clickhouse-client --query "INSERT INTO logs.events FORMAT JSONEachRow" < events.ndjson
clickhouse-client --query "INSERT INTO logs.events SELECT * FROM file('events.csv', CSVWithNames)"
clickhouse-client --query "SELECT count(), uniqExact(user_id) FROM logs.events"
clickhouse-client --query "SELECT service, quantile(0.95)(duration_ms) AS p95 FROM logs.events GROUP BY service ORDER BY p95 DESC"

Приложения отправляют пачки раз в несколько секунд: мелкие вставки создают лишние парты. Следите за ними через system.parts и system.merges.

Агрегаты и материализованные представления

Аналитические запросы в ClickHouse пишутся почти как в обычном SQL, но с функциями для приблизительных и точных агрегатов: uniq, uniqExact, quantile, topK.

Если один и тот же тяжёлый агрегат нужен постоянно, постройте материализованное представление на AggregatingMergeTree. Оно хранит промежуточные состояния, а не готовые числа, и объединяет их при чтении.

CREATE MATERIALIZED VIEW logs.events_hourly
ENGINE = AggregatingMergeTree
PARTITION BY toYYYYMM(hour)
ORDER BY (service, hour)
AS SELECT
    service,
    toStartOfHour(ts) AS hour,
    countState() AS requests,
    uniqState(user_id) AS users,
    quantileState(0.95)(duration_ms) AS p95
FROM logs.events
GROUP BY service, hour;

Читать такое представление нужно через countMerge, uniqMerge и quantileMerge. Обычный SELECT requests вернёт бинарное состояние, а не число — это самая частая ошибка новичков.

Обслуживание: парты, мутации и TTL

TTL автоматически удаляет устаревшие данные во время фоновых слияний. Удаление строк через ALTER TABLE ... DELETE создаёт мутацию, которая переписывает парты и может идти часами. Для массовой очистки лучше удалять целые партиции.

SELECT partition, rows, formatReadableSize(bytes_on_disk) AS size
FROM system.parts
WHERE table = 'events' AND active
ORDER BY partition DESC;

ALTER TABLE logs.events DROP PARTITION '202501';
SELECT * FROM system.mutations WHERE is_done = 0;
OPTIMIZE TABLE logs.events FINAL;

OPTIMIZE ... FINAL схлопывает парты и применяет TTL, но на большой таблице это тяжёлая операция. Проверяйте system.mutations, если ALTER завис.

Резервное копирование

Встроенная команда BACKUP умеет писать на локальный диск или в S3. Для неё в конфигурации должен быть описан диск назначения.

BACKUP TABLE logs.events TO Disk('backups', 'events.zip');
RESTORE TABLE logs.events FROM Disk('backups', 'events.zip');
SELECT * FROM system.backups ORDER BY start_time DESC LIMIT 5;

Для больших кластеров удобнее clickhouse-backup: он умеет инкрементальные копии и загрузку в объектное хранилище.

Диагностика и настройка

При проблемах смотрите system.query_log (медленные запросы), system.processes (что выполняется сейчас), system.merges и system.replicas для кластера. Ограничения памяти задаются на пользователя, а не глобально, поэтому один тяжёлый отчёт не должен ронять остальные.

  • Ставьте max_memory_usage и max_execution_time для пользователей дашбордов.
  • Не выбирайте SELECT * из широких таблиц: колоночное чтение экономит только при явном списке полей.
  • Фильтруйте по ключу сортировки, иначе индекс не поможет.
  • Следите за количеством активных партов: сотни на партицию — повод разобраться.

Итог

ClickHouse — не универсальная база, а инструмент под конкретную задачу: быстрый анализ больших объёмов событий. Начните с одной таблицы MergeTree, продуманного ORDER BY и месячных партиций, загружайте данные батчами и проверяйте план через system.query_log. Материализованные представления добавляйте только после того, как увидели реально медленный запрос.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте