ClickHouseCODECкомпрессияоптимизацияхранилище

ClickHouse CODEC: LZ4 vs ZSTD vs Delta vs T64 — компрессия per column

2026-06-02 10 мин

ClickHouse сжимает каждую колонку отдельно. И не одним алгоритмом — а цепочкой. Сначала Delta (вычитает значения), потом T64 (битовая упаковка), потом ZSTD (общая компрессия). Каждая колонка может иметь СВОЙ CODEC.

Этот гайд — практический выбор CODEC для разных типов данных, бенчмарки и где люди ошибаются.


Зачем менять CODEC

По умолчанию все колонки сжимаются LZ4. Это быстрая, но не самая плотная компрессия. Конкретные кейсы где default-вариант плох:

Экономия 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),
  ...
)

LZ4HC — slow encode, fast decode, выше ratio. Используют для редко-меняющихся (cold) данных.


ZSTD — плотнее, чуть медленнее

event_id UInt64 CODEC(ZSTD(3))  -- 3 — level (1-22), 3 — баланс

Бенчмарк (типичная events таблица 100M строк):

CODECCompressed sizeDecompress speed
LZ4 (default)4.2 GB1.0×
ZSTD(3)2.8 GB0.85×
ZSTD(9)2.4 GB0.6×
ZSTD(22)2.1 GB0.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);  -- ВАЖНО: данные физически отсортированы

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))


T64 — битовая упаковка для коротких чисел

T64 — packs N значений в M бит, используя только минимально нужные биты. Магия для small integers.

order_quantity UInt32 CODEC(T64, LZ4)

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)


Шаг 2: подбери CODEC по типу данных

Тип данныхРекомендация
Timestamps (sorted)CODEC(Delta, ZSTD(3))
Sequential IDsCODEC(Delta(8), LZ4)
Counters / small intsCODEC(T64, LZ4)
Floats (monitoring)CODEC(Gorilla, LZ4)
Text / logsCODEC(ZSTD(3)) или ZSTD(9)
Enums / low-cardinalityLowCardinality (не CODEC, отдельная фича)
JSON / stringsCODEC(ZSTD(3))
Random integersCODEC(LZ4) default
Booleans / flagsCODEC(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.

Смежные посты

Сравнить Free и Pro → (1999₽/мес, экономит часы рутины)

Источники

SQL-тренажёр
Тренируйся на SQL-задачах: настоящий PostgreSQL 16 + SQLite. 491 задача, бесплатно первые 5.
Открыть тренажёр →