ClickHouse сжимает каждую колонку отдельно. И не одним алгоритмом — а цепочкой. Сначала Delta (вычитает значения), потом T64 (битовая упаковка), потом ZSTD (общая компрессия). Каждая колонка может иметь СВОЙ CODEC.
Этот гайд — практический выбор CODEC для разных типов данных, бенчмарки и где люди ошибаются.
Зачем менять CODEC
По умолчанию все колонки сжимаются LZ4. Это быстрая, но не самая плотная компрессия. Конкретные кейсы где default-вариант плох:
- Timestamps — отлично сжимаются Delta + T64 (×10-50 vs LZ4)
- Sorted IDs — Delta + T64 (×5-20)
- Text logs — ZSTD level 3+ (×2-3 vs LZ4)
- Floats без паттерна — LZ4 = норма, ZSTD = маргинальный выигрыш
Экономия 10-30% storage — норма после оптимизации CODEC. Для таблицы 10TB это 1-3TB.
Шаг 1: посмотри текущую компрессию
Прежде чем менять — измерь, что есть.
SELECT
table,
name AS column,
type,
formatReadableSize(data_compressed_bytes) AS compressed,
formatReadableSize(data_uncompressed_bytes) AS uncompressed,
round(data_uncompressed_bytes / data_compressed_bytes, 1) AS ratio
FROM system.columns
WHERE database = 'analytics' AND table = 'events'
ORDER BY data_uncompressed_bytes DESC;
Низкий ratio (<3x) — там можно улучшить. High ratio (>20x) — уже хорошо, не трогай.
LZ4 — default, быстрый, средний
CREATE TABLE events (
event_id UInt64 CODEC(LZ4),
...
)
- Скорость декомпрессии: топ
- Ratio: 2-4× обычно
- Когда: всё, что не подходит под спец-CODEC
LZ4HC — slow encode, fast decode, выше ratio. Используют для редко-меняющихся (cold) данных.
ZSTD — плотнее, чуть медленнее
event_id UInt64 CODEC(ZSTD(3)) -- 3 — level (1-22), 3 — баланс
- Скорость декомпрессии: ~80% от LZ4
- Ratio: 3-5× обычно (для текста — 4-7×)
- Когда: текстовые колонки, логи, JSONB-данные
Бенчмарк (типичная events таблица 100M строк):
| CODEC | Compressed size | Decompress speed |
|---|---|---|
| LZ4 (default) | 4.2 GB | 1.0× |
| ZSTD(3) | 2.8 GB | 0.85× |
| ZSTD(9) | 2.4 GB | 0.6× |
| ZSTD(22) | 2.1 GB | 0.2× |
ZSTD(3) — sweet spot для большинства кейсов. Уровни 9+ — для cold storage где скорость не критична.
Delta — для отсортированных числовых
Delta хранит разницы между соседними значениями. Магия в том, что для отсортированных timestamps / IDs разницы — маленькие числа, которые потом отлично жмутся.
CREATE TABLE events (
event_ts DateTime64 CODEC(Delta, ZSTD(3)), -- сначала Delta, потом ZSTD
user_id UInt64 CODEC(Delta(8), LZ4)
)
ENGINE = MergeTree
ORDER BY (event_ts, user_id); -- ВАЖНО: данные физически отсортированы
- Когда: timestamps, увеличивающиеся IDs (sequential), versioned columns
- Ограничение: данные должны быть отсортированы на диске (через ORDER BY)
- Ratio: ×10-50 для timestamps
Delta(N) — N байт на разницу. Для int64 timestamps обычно Delta(8). Default Delta без N — auto-detect.
DoubleDelta — для «равно растущих»
DoubleDelta = Delta от Delta. Для строго равномерно растущих значений (например, событие каждую секунду) — ×100+ compression.
event_ts DateTime CODEC(DoubleDelta, ZSTD(3))
- Когда: high-frequency events с почти равными интервалами (sensor data, ticks)
- Не подходит: random timestamps (пользовательские события — bursty, не равномерные)
T64 — битовая упаковка для коротких чисел
T64 — packs N значений в M бит, используя только минимально нужные биты. Магия для small integers.
order_quantity UInt32 CODEC(T64, LZ4)
- Когда: short integers (счётчики, флаги, ID < 65535), enum-like
- Ratio: ×4-15 vs raw
Delta + T64 + LZ4 — частая цепочка для time-series counters. Например:
events_per_user UInt32 CODEC(Delta, T64, LZ4)
Gorilla — для float-метрик (мониторинг)
Gorilla — алгоритм Facebook для time-series метрик. Сжимает floats путём storing только различия от предыдущего значения через XOR.
metric_value Float64 CODEC(Gorilla, LZ4)
- Когда: monitoring metrics (CPU, memory, latency)
- Ratio: ×5-20 для smooth-меняющихся метрик
- Не подходит: random floats без correlation
Шаг 2: подбери CODEC по типу данных
| Тип данных | Рекомендация |
|---|---|
| Timestamps (sorted) | CODEC(Delta, ZSTD(3)) |
| Sequential IDs | CODEC(Delta(8), LZ4) |
| Counters / small ints | CODEC(T64, LZ4) |
| Floats (monitoring) | CODEC(Gorilla, LZ4) |
| Text / logs | CODEC(ZSTD(3)) или ZSTD(9) |
| Enums / low-cardinality | LowCardinality (не CODEC, отдельная фича) |
| JSON / strings | CODEC(ZSTD(3)) |
| Random integers | CODEC(LZ4) default |
| Booleans / flags | CODEC(T64, LZ4) |
Шаг 3: примени и измерь
-- Создай новую таблицу с CODEC
CREATE TABLE events_v2 (
event_id UInt64 CODEC(LZ4),
event_ts DateTime CODEC(Delta, ZSTD(3)),
user_id UInt64 CODEC(Delta(8), LZ4),
event_type LowCardinality(String),
payload String CODEC(ZSTD(3))
) ENGINE = MergeTree
ORDER BY (event_ts, user_id);
-- Перелей данные
INSERT INTO events_v2 SELECT * FROM events;
-- Сравни размеры
SELECT
'events' AS tbl, formatReadableSize(sum(data_compressed_bytes)) AS size
FROM system.columns WHERE table = 'events'
UNION ALL
SELECT
'events_v2', formatReadableSize(sum(data_compressed_bytes))
FROM system.columns WHERE table = 'events_v2';
Шаг 4: применить CODEC к existing таблице
Нельзя поменять CODEC через ALTER TABLE на колонке у которой уже есть данные. Workaround — через MODIFY COLUMN + OPTIMIZE:
-- 1. Меняем DDL (CODEC применится для новых данных)
ALTER TABLE events MODIFY COLUMN event_ts DateTime CODEC(Delta, ZSTD(3));
-- 2. Принудительный re-write всех partition'ов (ОЧЕНЬ ДОРОГО на большой таблице)
OPTIMIZE TABLE events FINAL;
На production-таблице 10TB — OPTIMIZE FINAL идёт часами и грузит диск. Лучше — создать new table + перелить через INSERT SELECT + RENAME.
Подводные камни
Грабли 1: Delta без ORDER BY = разочарование
Если данные на диске не отсортированы — Delta не работает (разницы будут случайные). Без ORDER BY (col, ...) где col — твоя «time» колонка — Delta бесполезен.
Грабли 2: ZSTD(22) — медленно decompress
Уровень 22 даёт ×1.1 vs ZSTD(3), но в 5× медленнее на decompress. Production-аналитика — этот уровень потеряет читателей. ZSTD(3-9) — sweet spot.
Грабли 3: LowCardinality vs CODEC
LowCardinality(String) — отдельный механизм (не CODEC). Использует dictionary encoding. Для колонок с <100k unique values — ×10-100 compression. ЛУЧШЕ чем любой CODEC для категориальных данных.
Грабли 4: T64 на больших числах
T64 работает с числами до 64 бит — но если у тебя in real range UInt64 значения с full range — T64 не поможет. Лучше LZ4.
Частые вопросы
Можно ли смешать CODEC?
Да: CODEC(Delta, T64, ZSTD(3)) — цепочка. ClickHouse применяет слева направо. Декомпрессия — наоборот.
Влияет ли CODEC на скорость SELECT?
Чуть-чуть. Decompression — ~5-15% overhead на CPU. Но если меньше I/O — total query latency ВЫШЕ.
Что использовать для String колонки?
ZSTD(3) — почти всегда. Если String low-cardinality (≤100k unique) — LowCardinality(String) без CODEC.
Можно ли использовать CODEC на primary key columns?
Да, но осторожно. Delta хорошо работает на sorted ключе. T64 — нет (мешает быстрому seek).
Стоит ли менять default LZ4 на ZSTD везде?
Нет. LZ4 быстрее decompress. Для hot queries (production dashboards) — LZ4. Для cold storage / logs — ZSTD.
Что дальше
Если хочешь практику — попробуй SQL-тренажёр с автопроверкой (5 задач бесплатно). PostgreSQL 16 в браузере + SQLite — повторяй любые SELECT-паттерны для подготовки к собесу.
Готов к собеседованиям? AI-интервью тренирует ответы на реальных вопросах из бесплатного пула. В Pro — безлимит мок-собесов с разбором + 491 SQL-задача + 612 тестовых заданий из реальных собесов 2026.
Смежные посты
- ClickHouse Materialized Views и Projections
- ClickHouse для аналитика — практический гайд
- PostgreSQL vs ClickHouse benchmarks
- Apache Iceberg vs Delta vs Hudi
Сравнить Free и Pro → (1999₽/мес, экономит часы рутины)
Источники
- ClickHouse Docs: «CODECs» (clickhouse.com/docs/sql-reference/statements/create/table#codecs)
- Habr 1014956: ClickHouse compression deep dive
- Cian Tech: «Iceberg + ClickHouse» (habr.com/859484)
- Pelin: «ZSTD vs LZ4 benchmarks» (pelin.dev)