Специализированные движки MergeTree

Семейство MergeTree — это не один движок, а набор под разные задачи.

Специализированные MergeTree — движки, которые во время фонового слияния дополнительно преобразуют данные: дедуплицируют, суммируют или агрегируют строки с одинаковым ключом.

Зачем варианты

Обычный MergeTree при слиянии просто складывает куски вместе. Но часто хочется большего: «оставлять только последнюю версию записи» или «суммировать метрики по ключу». Чтобы не делать это запросами каждый раз, ClickHouse предлагает движки, которые делают преобразование сами при слиянии.

ReplacingMergeTree — дедупликация

Оставляет только одну (обычно последнюю по версии) строку на каждый ключ ORDER BY. Удобно, когда данные могут приходить повторно:

CREATE TABLE users
(
    user_id UInt32,
    name    String,
    version UInt32
)
ENGINE = ReplacingMergeTree(version)
ORDER BY user_id;

Важный нюанс: дедупликация происходит при слиянии, не мгновенно. До слияния дубликаты ещё видны — чтобы гарантированно получить свёрнутый результат, добавляют FINAL к запросу.

SummingMergeTree — суммирование

При слиянии складывает числовые колонки у строк с одинаковым ключом. Идеален для счётчиков:

CREATE TABLE counters
(
    page  String,
    day   Date,
    hits  UInt64
)
ENGINE = SummingMergeTree
ORDER BY (page, day);

Вставили десять строк «страница X, день Y, +1» — после слияния останется одна строка с hits = 10.

AggregatingMergeTree — любые агрегаты

Обобщение SummingMergeTree: умеет хранить не только суммы, но и состояния любых агрегатных функций (например, uniq, avg) через типы AggregateFunction. Чаще всего используется вместе с материализованными представлениями (отдельный раздел).

CollapsingMergeTree — отмена строк

Хранит «знак» (+1/-1) и при слиянии схлопывает пары «добавили/отменили», оставляя итог. Применяется, когда нужно изменять уже записанные агрегаты без UPDATE.

Сводка

ДвижокЧто делает при слиянии
MergeTreeничего особенного — просто хранит
ReplacingMergeTreeоставляет одну версию на ключ
SummingMergeTreeсуммирует числа по ключу
AggregatingMergeTreeсворачивает любые агрегатные состояния
CollapsingMergeTreeсхлопывает пары по знаку

Как работает под капотом

Все эти движки наследуют механику MergeTree (куски, ORDER BY, индекс), но переопределяют шаг слияния: при объединении строк с одинаковым ключом применяют своё правило. Поэтому результат «свёрнут» только после слияния, а до него возможны промежуточные строки.

Частые ошибки

  • Ждать мгновенной дедупликации/суммы. Преобразование происходит при слиянии; до него запрос видит «сырые» строки. Используйте FINAL или агрегируйте в запросе.
  • Неправильный ORDER BY. Свёртка идёт по ключу ORDER BY — если он не тот, строки не схлопнутся как ожидалось.
  • Тяжёлый FINAL на больших данных. Он дорог; часто лучше агрегировать в самом SELECT.

Итоги

  • MergeTree — целое семейство движков под разные задачи.
  • Replacing — дедупликация, Summing — суммы, Aggregating — любые агрегаты, Collapsing — отмена.
  • Преобразование происходит при слиянии, а не сразу — учитывайте это в запросах.
Проверьте себя
1. Какой движок оставит одну (последнюю) версию строки на каждый ключ?
ASummingMergeTree
BReplacingMergeTree
CMergeTree
DCollapsingMergeTree
2. Почему после вставки дубликатов в ReplacingMergeTree запрос всё ещё может их показывать?
AЭто баг
BДедупликация происходит при фоновом слиянии, а не мгновенно
CНужно перезапустить сервер
DReplacingMergeTree не умеет дедупликацию