Materialized view сохраняет результат вычисления для последующего чтения. Обычная VIEW хранит запрос и выполняет его при обращении. В ClickHouse есть два режима materialized view: обработка вставляемых блоков и периодический пересчёт запроса.
Инкрементальная view
Incremental materialized view выполняет SELECT над очередным вставленным блоком источника и записывает результат в целевую таблицу. Она переносит часть работы со времени чтения на время загрузки.
Пусть events хранит event_time и event_type, а daily_events принимает day, event_type и total. Счётчик можно описать так:
CREATE MATERIALIZED VIEW daily_events_insert
TO daily_events AS
SELECT
toDate(event_time) AS day,
event_type,
count() AS total
FROM events
GROUP BY day, event_type;TO обозначает уже существующую target-таблицу. Если она использует SummingMergeTree с ключом (day, event_type), то сохраняет и объединяет частичные счётчики. На чтении нужен sum(total) с GROUP BY: фоновые merges могли ещё не завершиться.
Первый блок с тремя click и второй с двумя дадут отдельные вклады 3 и 2; запрос объединит их в 5. Для средних передают сумму и количество или состояние агрегата.
Что запускает вычисление
Триггер — вставка в исходную таблицу. Merge, mutation, DELETE и TTL источника не запускают пересчёт ранее записанного результата. Замена старых версий в ReplacingMergeTree тоже не отменяет уже учтённые вклады.
Если SELECT view содержит JOIN со справочником, вставка в основной источник может использовать справочник. Изменение правой таблицы само по себе не пересчитывает витрину. Нужно определить, хранится атрибут на момент события или ожидается его актуальное значение.
Цепочка views увеличивает работу и число точек ошибки при INSERT. Обработку ошибок и повторов проверяют для каждой целевой таблицы: частично выполненная цепочка может оставить результаты только в части из них.
Существующая история
Создание incremental view не загружает старые строки автоматически. Backfill — отдельная вставка рассчитанного исторического результата в target. При продолжающейся загрузке нужно разделить старую историю и новые события так, чтобы не возникли пропуски или двойной вклад.
При конкурентных вставках POPULATE может пропустить новые строки; доступность этой опции зависит от формы view. Для backfill задают границу по времени или версии и сверяют исторический результат с исходником.
Refreshable materialized view
Refreshable view периодически выполняет запрос над доступными данными целиком. Она подходит для сложных соединений, исправлений истории и результата, который допустимо обновлять с задержкой.
CREATE MATERIALIZED VIEW refreshed_counts
REFRESH EVERY 1 HOUR
ENGINE = MergeTree
ORDER BY event_type AS
SELECT event_type, count() AS total
FROM events
GROUP BY event_type;По умолчанию завершённый пересчёт атомарно заменяет предыдущий результат. Во время вычисления читатель продолжает видеть старую готовую версию. Режим APPEND добавляет новые результаты вместо замены; он требует отдельного смысла для накопленных снимков.
При каждом пересчёте view снова читает вход и расходует ресурсы. Между изменением источника и следующим успешным refresh остаётся задержка. Инкрементальный подход выбирают для корректно объединяемых новых вкладов, refreshable — когда проще заново получить согласованный результат из текущего источника.