Сжатие данных
Сжатие в ClickHouse — не только про экономию места, но и про скорость.
Кодек (codec) — алгоритм сжатия, применяемый к колонке; ClickHouse сжимает все данные по умолчанию, а кодек можно выбрать под характер колонки.
Почему сжатие ускоряет запросы
Кажется парадоксом: распаковка тратит процессорное время — разве это не замедляет? На практике наоборот. Узкое место — диск, а не CPU. Сжатые данные занимают меньше места, значит с диска нужно прочитать меньше байт. Современный процессор распакует их быстрее, чем диск прочёл бы несжатый объём. Итог: меньше чтения → быстрее запрос.
несжатая колонка: [====== много байт с диска ======] медленно сжатая колонка: [== мало байт ==] + распаковка на CPU быстрее
Кодеки общего назначения
| Кодек | Профиль |
LZ4 (по умолчанию) | очень быстрый, умеренное сжатие |
ZSTD | сильнее жмёт, чуть медленнее |
LZ4 — баланс по умолчанию. Для «холодных» данных, которые редко читают, но хочется хранить компактно, берут ZSTD (с уровнем, например ZSTD(3)).
Специализированные кодеки
Под определённые данные есть кодеки, которые радикально уменьшают объём до общего сжатия:
Delta— хранит разницы между соседними значениями. Идеален для почти упорядоченных колонок (id, время).DoubleDelta— разница разниц; отлично жмёт равномерно растущие временные ряды.Gorilla— для медленно меняющихся чисел с плавающей точкой (метрики).
Кодеки можно комбинировать: сначала специализированный, потом общий.
CREATE TABLE metrics
(
ts DateTime CODEC(DoubleDelta, LZ4),
host LowCardinality(String),
value Float64 CODEC(Gorilla, LZ4)
)
ENGINE = MergeTree
ORDER BY (host, ts);Идея Delta на практике
Вспомним delta-кодирование из раздела про колоночное хранение — оно и лежит в основе кодека Delta (чистый Python):
ids = [1000, 1001, 1002, 1003, 1004]
delta = [ids[0]] + [ids[i] - ids[i-1] for i in range(1, len(ids))]
print("Было: ", ids)
print("Delta: ", delta)Вывод:
Было: [1000, 1001, 1002, 1003, 1004] Delta: [1000, 1, 1, 1, 1]
Колонка из единиц жмётся почти в ничто — поэтому Delta так эффективен для последовательных значений.
Как работает под капотом
ClickHouse сжимает данные блоками (по умолчанию ~64 КБ или гранулами). При чтении распаковываются только нужные блоки нужных колонок. Кодек указывается на уровне колонки в CODEC(...), и для разных колонок выгодны разные кодеки.
Частые ошибки
- Считать, что сжатие замедляет. На деле меньше чтения с диска обычно ускоряет аналитику.
- Везде ZSTD с высоким уровнем. Для «горячих» часто читаемых данных это лишний расход CPU; LZ4 быстрее.
- Игнорировать спецкодеки для рядов. Для времени и счётчиков
Delta/DoubleDeltaдают огромную экономию.
Итоги
- Сжатие уменьшает чтение с диска и обычно ускоряет аналитику.
LZ4— быстрый дефолт,ZSTD— сильнее жмёт для холодных данных.- Спецкодеки
Delta/DoubleDelta/Gorilla— для рядов и метрик. - Кодеки задаются на уровне колонки и комбинируются.