Перейти к основному содержанию
Этот пример показывает, как создать materialized view, а затем каскадно построить вторую materialized view поверх первой. На этой странице вы увидите, как это сделать, какие для этого есть возможности и какие существуют ограничения. Разные сценарии использования можно реализовать, создав materialized view, которая использует другую materialized view в качестве источника.

Пример: Мы будем использовать фиктивный набор данных с количеством просмотров в час для набора доменных имён. Наша цель
  1. Нам нужны данные, агрегированные по месяцам для каждого доменного имени,
  2. Нам также нужны данные, агрегированные по годам для каждого доменного имени.
Вы можете выбрать один из следующих вариантов:
  • Писать запросы, которые будут читать и агрегировать данные во время выполнения SELECT-запроса
  • Подготовить данные во время приёма в новом формате
  • Подготовить данные во время приёма в виде определённой агрегации.
Подготовка данных с помощью materialized views позволит сократить объём данных и вычислений, которые ClickHouse должен выполнять, и тем самым ускорить ваши SELECT-запросы.

Исходная таблица для materialized views

Создайте исходную таблицу: поскольку наша цель — строить отчёты по агрегированным данным, а не по отдельным строкам, мы можем разобрать входящие данные, передать нужную информацию в Materialized Views и отбросить сами данные. Это соответствует нашим целям и позволяет сэкономить место в хранилище, поэтому мы будем использовать движок таблицы Null.
Вы можете создать materialized view на таблице Null. Тогда данные, записываемые в таблицу, будут влиять на materialized view, но исходные необработанные данные по-прежнему будут отбрасываться.

Ежемесячная aggregated table и materialized view

Для первого materialized view нам нужно создать целевую table Target; в этом примере это будет analytics.monthly_aggregated_data, где мы будем хранить сумму просмотров по месяцам и доменным именам.
materialized view, которое будет передавать данные в целевую таблицу, будет выглядеть так:

Ежегодно агрегированная таблица и materialized view

Теперь мы создадим второе materialized view, которое будет связано с предыдущей целевой таблицей monthly_aggregated_data. Сначала мы создадим новую целевую таблицу, в которой будет храниться суммарное количество просмотров, агрегированное по годам для каждого доменного имени.
На этом шаге определяется каскад. Оператор FROM будет использовать таблицу monthly_aggregated_data, то есть поток данных будет таким:
  1. Данные поступают в таблицу hourly_data.
  2. ClickHouse перенаправит полученные данные в первую materialized view — monthly_aggregated_data,
  3. Наконец, данные, полученные на шаге 2, будут перенаправлены в year_aggregated_data.
Распространённое заблуждение при работе с materialized view состоит в том, что данные читаются из таблицы. Materialized views работают не так: пересылается не итоговый результат в таблице, а вставленный блок данных.Представим, что в этом примере в monthly_aggregated_data используется движок CollapsingMergeTree. Данные, передаваемые в наше второе materialized view year_aggregated_data_mv, не будут итоговым результатом схлопнутой таблицы; будет передан блок данных с полями, определёнными в SELECT ... GROUP BY.Если вы используете CollapsingMergeTree, ReplacingMergeTree или даже SummingMergeTree и планируете создать каскадное materialized view, вам нужно понимать описанные здесь ограничения.

Пример данных

Теперь протестируем наше каскадное materialized view, вставив немного данных:
Если вы выполните SELECT для содержимого analytics.hourly_data, то увидите следующее, потому что движок таблицы — Null, хотя данные были обработаны.
Мы использовали небольшой набор данных, чтобы можно было отследить и сравнить результат с ожидаемым; когда ваш поток будет правильно работать на небольшом наборе данных, вы сможете просто перейти к большому объёму данных.

Результаты

Если вы попытаетесь выполнить запрос к целевой таблице, выбрав поле sumCountViews, то увидите бинарное представление (в некоторых терминалах), поскольку значение хранится не как число, а как тип AggregateFunction. Чтобы получить итоговый результат агрегации, следует использовать суффикс -Merge. Специальные символы, хранящиеся в AggregateFunction, можно увидеть с помощью этого запроса:
Вместо этого давайте попробуем использовать суффикс Merge, чтобы получить значение sumCountViews:
В AggregatingMergeTree мы определили AggregateFunction как sum, поэтому можем использовать sumMerge. Если в AggregateFunction используется функция avg, то следует использовать avgMerge, и так далее.
Теперь мы можем убедиться, что materialized views позволяют достичь поставленной нами цели. Теперь, когда данные хранятся в целевой таблице monthly_aggregated_data, мы можем получить агрегированные по месяцам данные для каждого доменного имени:
Данные по каждому доменному имени, агрегированные по годам:

Объединение нескольких исходных таблиц в одну целевую таблицу

materialized views также можно использовать, чтобы объединять несколько исходных таблиц в одну целевую таблицу. Это полезно, когда нужно создать materialized view с логикой, аналогичной UNION ALL. Сначала создайте две исходные таблицы, представляющие разные наборы метрик:
Затем создайте таблицу Target с объединённым набором метрик:
Создайте два materialized view, направленных на одну и ту же таблицу Target. Отсутствующие столбцы не нужно указывать явно:
Теперь при вставке значений они будут агрегироваться в соответствующих столбцах таблицы Target:
Объединённые показы и клики в таблице Target:
Этот запрос должен вернуть что-то вроде:
Последнее изменение 1 июля 2026 г.