ClickHouse 21.10 Projections: 4 секунды -> 80 мс без изменения структуры данных
ClickHouse 21.10 добавил Projections - преагрегированные представления внутри таблицы. Тестируем на дашборде с 50 млн строк, разбираем cost и ограничения.
ClickHouse 21.10 представляет Projections - преагрегированные представления внутри таблицы для ускорения аналитических запросов
ClickHouse 21.10 вышел в конце октября, и в нём появилась фича, которую обсуждали на форуме уже несколько месяцев: Projections. Если коротко - это способ держать преагрегированные данные внутри той же таблицы, без отдельных материализованных представлений и без изменения запросов в приложении. Мы потестировали на одном из клиентских дашбордов. Результат оказался интереснее, чем ожидали.
Что такое Projections и зачем они нужны
Классическая проблема для DWH-аналитики на ClickHouse: таблица с сотнями миллионов строк хранит сырые события, а дашборд регулярно гоняет один и тот же агрегирующий запрос - SUM, COUNT, группировка по двум-трём измерениям. ClickHouse быстрый, но не бесконечно: на 50 млн строк с несколькими фильтрами это 3-5 секунд, и при нескольких одновременных пользователях начинает ощущаться.
До 21.10 стандартный ответ был такой: создать Materialized View, которое при вставке строит агрегат в отдельную таблицу, и переписать запросы дашборда на эту таблицу. Работает, но у подхода две неприятности. Первая - нужно менять запросы или добавлять логику маршрутизации на уровне приложения. Вторая - матвью и основная таблица живут отдельно: если основная таблица перестраивается или меняется схема, матвью надо пересоздавать вручную.
Projections решают это иначе. Projection хранится физически внутри той же таблицы как дополнительный отсортированный кусок данных с другим порядком сортировки или преагрегацией. ClickHouse сам решает при выполнении запроса - использовать основные данные или projection. Запросы в приложении не меняются вообще.
Что и как мерили
Стенд: таблица примерно в 50 млн строк, данные типичного event log - пользователь, продукт, дата, сумма, регион. Основная сортировка таблицы по (date, user_id). Запрос дашборда агрегирует суммы по product_id и region_id с фильтром по диапазону дат - порядка месяца.
До добавления Projection этот запрос выполнялся около 4 секунд. ClickHouse читал полный диапазон дат из основного индекса, а дальше агрегировал по product_id / region_id - столбцы, которые не участвуют в первичном ключе таблицы и потому не помогают с pruning.
Добавляем Projection:
ALTER TABLE events
ADD PROJECTION agg_product_region
(
SELECT
toYYYYMM(date) AS month,
product_id,
region_id,
sum(amount) AS total_amount,
count() AS cnt
GROUP BY month, product_id, region_id
);
-- материализуем на существующих данных
ALTER TABLE events MATERIALIZE PROJECTION agg_product_region;
Материализация на 50 млн строк заняла около 8 минут - один раз, при добавлении. После этого всё. Тот же запрос дашборда без каких-либо изменений в коде - 80-100 мс вместо 4 секунд. ClickHouse автоматически перехватил запрос и пошёл в projection.
Как ClickHouse выбирает projection
Это важно понимать, чтобы не удивляться потом. ClickHouse анализирует запрос при выполнении и проверяет: может ли какой-либо projection ответить на этот запрос. Критерий - все колонки в SELECT и WHERE должны быть покрыты projection'ом, и projection должен дать меньше данных на вход. Если условия выполнены - ClickHouse использует projection. Если нет - идёт в основную таблицу.
EXPLAIN покажет выбор:
EXPLAIN SELECT toYYYYMM(date) AS month, product_id, sum(amount)
FROM events
WHERE date >= '2021-10-01' AND date < '2021-11-01'
GROUP BY month, product_id;
В поле ReadFromStorage будет видно имя projection или отсутствие - тогда читается основная таблица.
Cost: что реально платишь
Место на диске. Projection хранится физически, это не виртуальная структура. На нашем стенде преагрегированный projection по месяцу/продукту/региону занял около 2% от размера основной таблицы - мелочь в данном случае. Но если сделать projection с высокой кардинальностью (например, по user_id + product_id без агрегации), он может занять сравнимо с основной таблицей.
Время вставки. При каждом INSERT ClickHouse строит projection параллельно с основными данными. На нашей нагрузке overhead незаметен - вставки батчами, projection небольшой. При агрессивной онлайн-вставке с маленькими батчами и тяжёлым projection это может стать узким местом.
Материализация при добавлении. MATERIALIZE PROJECTION - это мутация, она идёт в фоне и нагружает диск. На большой таблице лучше делать в нерабочее время.
Ограничения, которые надо знать
Projection с GROUP BY не работает на запросах без агрегации. Звучит очевидно, но на практике: если дашборд иногда гоняет и агрегирующий запрос, и детализированный по той же таблице - для детализации projection не поможет.
Нет явного управления. Нельзя сказать «используй этот projection для этого запроса». ClickHouse решает сам. Если projection не подходит по схеме - молча идёт в основную таблицу, запрос не падает с ошибкой. Нужно проверять через EXPLAIN.
DDL-изменения таблицы. ALTER TABLE ... ADD COLUMN проходит нормально, projection наследует новый столбец если он туда включён. Но если изменить столбец, который участвует в projection - projection нужно пересоздать. Это предсказуемо, но про это легко забыть при активной разработке схемы.
Несколько Projections на одну таблицу - поддерживается, и каждый будет материализоваться и занимать место независимо. Не стоит создавать их на каждый запрос без разбора.
Сравнение с Materialized View
Принципиальная разница: матвью - отдельная таблица, projection - часть основной. При изменении данных в основной таблице (OPTIMIZE, мутации) projection актуализируется автоматически. Матвью этого не делает - там данные только из INSERT-потока.
Для нашего сценария (дашборд с фиксированным набором агрегатов поверх append-only таблицы событий) Projection оказался удобнее: не нужно менять запросы, всё живёт в одном месте, структура прозрачна. Для сценариев где нужно сложное преобразование данных при вставке или несколько destination-таблиц - матвью по-прежнему уместнее.
Фича молодая - в 21.10 это ещё beta-уровень по документации ClickHouse. Мы не идём с этим в продакшн немедленно, но на стенде поведение стабильное и результат убедительный. Будем наблюдать ещё пару релизов.
Аналитическую инфраструктуру на ClickHouse строим и поддерживаем в рамках DWH и бизнес-аналитики.