Агрегатные комбинаторы: -If, -Array, -State/-Merge
Один суффикс превращает обычную агрегатную функцию в новый инструмент.
Комбинатор — суффикс, добавляемый к имени агрегатной функции (например,
sumIf,uniqState), который меняет её поведение.
Идея комбинаторов
Вместо десятков отдельных функций ClickHouse даёт «конструктор»: берёте любую агрегатную функцию и приклеиваете суффикс. Так из sum получается sumIf, sumArray, sumState. Разберём главные.
-If: условная агрегация
Суффикс -If добавляет функции дополнительный аргумент-условие — агрегируются только строки, где оно истинно. Это позволяет посчитать несколько срезов за один проход по данным:
SELECT
count() AS all_events,
countIf(country = 'RU') AS ru_events,
sumIf(amount, status = 'paid') AS paid_revenue,
avgIf(duration, success = 1) AS avg_ok_duration
FROM events;Без -If пришлось бы делать несколько отдельных запросов или громоздкие CASE.
-Array: агрегация по массивам
Суффикс -Array применяет функцию к элементам массивов в колонке, как будто они «развёрнуты». Если в колонке tags лежат массивы строк, uniqArray(tags) посчитает уникальные теги по всем массивам сразу.
-State и -Merge: самое мощное
Это пара для предагрегации. Обычная функция возвращает готовое число. Функция с суффиксом -State возвращает промежуточное состояние агрегата — компактный «полуфабрикат» (например, скетч для uniq или пару «сумма+счётчик» для avg), который можно сохранить и потом доагрегировать.
-- Сохраняем состояния (не финальные числа), например в таблицу с AggregatingMergeTree:
SELECT
day,
uniqState(user_id) AS users_state,
avgState(duration) AS dur_state
FROM events
GROUP BY day;Позже из этих состояний получаем финальный результат функцией с суффиксом -Merge, причём можем дополнительно сворачивать (например, дни в недели):
SELECT
toStartOfWeek(day) AS week,
uniqMerge(users_state) AS weekly_users,
avgMerge(dur_state) AS weekly_avg_dur
FROM daily_states
GROUP BY week;Почему -State/-Merge так важны
Состояния складываемы: состояние за день + состояние за день = состояние за два дня. Поэтому можно один раз свернуть сырые события в посуточные состояния (мало строк), а потом мгновенно собирать из них отчёты за любой период — не трогая исходные миллиарды строк. На этом построены материализованные представления (следующий раздел).
Памятка
| Суффикс | Что делает |
-If | агрегирует только по условию |
-Array | агрегирует по элементам массивов |
-State | возвращает промежуточное состояние |
-Merge | сворачивает состояния в финал |
Как работает под капотом
Состояние агрегата — это сериализованная внутренняя структура функции (для avg — сумма и количество, для uniq — HyperLogLog-скетч). Тип такого столбца — AggregateFunction(...). -Merge объединяет несколько состояний так же, как это делается при параллельном вычислении на разных ядрах.
Частые ошибки
- Складывать готовые
uniq-числа. Сумма уникальных по дням ≠ уникальные за неделю (один и тот же пользователь посчитается дважды). Складывать нужно состояния через-State/-Merge. - Читать состояние как обычное число. Колонку
AggregateFunctionнужно «финализировать» через-Merge, иначе получите нечитаемый бинарный объект. - Громоздкие
CASEвместо-If.countIf/sumIfчище и быстрее для срезов.
Итоги
- Комбинаторы — суффиксы, расширяющие агрегатные функции.
-If— условные срезы за один проход;-Array— работа с массивами.-State/-Merge— складываемые промежуточные состояния для предагрегации.- Уникальные нельзя суммировать как числа — только через состояния.