Что такое ClickHouse, история создания, область применения, колоночная архитектура, векторизованное выполнение
Как устройство хранения превращается в стоимость запроса
Вы сможете объяснить путь данных от INSERT до фонового merge, оценить объём чтения аналитического запроса и решить, подходит ли ClickHouse конкретной нагрузке.
ClickHouse — колоночная OLAP-система (Online Analytical Processing) с открытым исходным кодом. Её начали разрабатывать в Яндексе для Метрики, где нужно было быстро считать отчёты по большим потокам событий.
ClickHouse создан для аналитических запросов к большим объёмам данных. Его сильные стороны проявляются, когда запрос читает несколько колонок, фильтрует и агрегирует много строк, а данные загружаются пакетами. Конкретная пропускная способность и степень сжатия зависят от схемы, распределения значений, оборудования и запроса — их нужно измерять на своём наборе данных.
Хорошие сценарии:
Традиционные строковые БД (PostgreSQL, MySQL) хранят данные по строкам:
Строка 1: | id=1 | name="Alice" | age=25 | city="Moscow" |
Строка 2: | id=2 | name="Bob" | age=30 | city="London" |
Строка 3: | id=3 | name="Carol" | age=28 | city="Paris" |
Для запроса SELECT AVG(age) FROM users нужно прочитать все колонки всех строк, даже если нужны только значения age.
Колоночные БД (ClickHouse) хранят данные по колонкам:
id: | 1 | 2 | 3 |
name: | Alice | Bob | Carol |
age: | 25 | 30 | 28 |
city: | Moscow | London | Paris |
Для того же запроса читается только колонка age — остальные игнорируются.
ClickHouse обрабатывает данные блоками и применяет функции к векторам значений:
# Вместо построчной обработки:
for row in rows:
result = row.age * 2 + 10
# ClickHouse использует векторные операции:
ages = [25, 30, 28, ...] # вектор значений
result = ages * 2 + 10 # одна SIMD-инструкция
Это позволяет использовать SIMD-инструкции процессора (SSE, AVX), которые выполняют одну операцию над несколькими значениями одновременно.
SIMD — один из механизмов ускорения, но не обещание фиксированного коэффициента. Запрос может упираться в диск, сеть, распаковку, хэш-таблицу JOIN или память.
┌─────────────────────────────────────────────────────────┐
│ ClickHouse Server │
├─────────────────────────────────────────────────────────┤
│ HTTP Interface (8123) │ Native Interface (9000) │
├─────────────────────────────────────────────────────────┤
│ SQL Parser & Optimizer │
├─────────────────────────────────────────────────────────┤
│ Query Executor │
│ (Vectorized, Pipeline-based) │
├─────────────────────────────────────────────────────────┤
│ Storage Engine Layer │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ MergeTree│ │ Log │ │ Memory │ │ Custom │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────┤
│ File System │
│ (Data Parts, Indexes, Logs) │
└─────────────────────────────────────────────────────────┘
Движок таблицы определяет способ хранения и обработки данных. В ClickHouse движков несколько:
| Семейство | Назначение | Примеры |
|---|---|---|
| MergeTree | Основное семейство для аналитики | MergeTree, ReplacingMergeTree, SummingMergeTree |
| Log | Простые таблицы для временных данных | Log, StripeLog, TinyLog |
| Memory | Данные в оперативной памяти | Memory, Set, Join |
| Интеграция | Работа с внешними источниками | MySQL, PostgreSQL, Kafka, HDFS |
| Специальные | Узкоспециализированные задачи | Null, File, URL, Dictionary |
MergeTree — основной движок для рабочей аналитики. Остальные нужны для более узких сценариев.
Читаем только нужные колонки и проверяем эффект по read_bytes.
Используем специализированные кодеки:
SIMD-инструкции процессора для параллельной обработки.
Первичный и data-skipping индексы исключают гранулы, если ключ и распределение данных соответствуют фильтрам запроса.
Автоматическое использование всех ядер CPU для выполнения запроса.
Данные хранятся отсортированными, что обеспечивает последовательное чтение с диска.
Не сравнивайте СУБД по цифрам без набора данных, DDL и настроек. Сначала измерьте два запроса в одном окружении:
SELECT count()
FROM events
WHERE tenant_id = 42;
SELECT event_time, event_type
FROM events
WHERE tenant_id = 42;После выполнения найдите их в system.query_log и сравните read_rows, read_bytes, memory_usage и query_duration_ms. Затем измените только одну вещь — например, порядок ключа сортировки — и повторите несколько запусков. Такой протокол объясняет причину ускорения; одиночное число не объясняет.
Далее: Установка и первое знакомство