Каскадные материализованные представления
Этот пример демонстрирует, как создать материализованное представление, а затем — как создать второе материализованное представление на основе первого (каскадно). На этой странице вы увидите, как это сделать, узнаете о многих возможностях и ограничениях. Разные варианты использования можно реализовать, создавая материализованное представление, использующее в качестве источника другое материализованное представление.
Пример:
Мы будем использовать искусственный набор данных с числом просмотров в час для группы доменных имён.
Наша цель:
- Нам нужны данные, агрегированные по месяцам для каждого доменного имени,
- Нам также нужны данные, агрегированные по годам для каждого доменного имени.
Вы можете выбрать один из следующих вариантов:
- Писать запросы, которые будут читать и агрегировать данные во время выполнения запроса SELECT
- Подготавливать данные во время приёма к новому формату
- Подготавливать данные во время приёма к определённой агрегации.
Подготовка данных с помощью материализованных представлений позволит ограничить объём данных и вычислений, которые ClickHouse должен выполнять, что сделает ваши запросы SELECT быстрее.
Исходная таблица для материализованных представлений
Создайте исходную таблицу. Поскольку наша цель — формировать отчёты по агрегированным данным, а не по отдельным строкам, мы можем разобрать входящие данные, передать информацию в материализованные представления и отбросить сами исходные данные. Это соответствует нашим целям и экономит место в хранилище, поэтому мы будем использовать движок таблицы Null.
Вы можете создать материализованное представление на таблице Null. Тогда данные, записанные в таблицу, будут влиять на представление, при этом исходные сырые данные всё равно будут отбрасываться.
Ежемесячная агрегированная таблица и материализованное представление
Для первого материализованного представления нужно создать таблицу Target. В этом примере это будет analytics.monthly_aggregated_data, где мы будем хранить сумму просмотров по месяцам и доменным именам.
Материализованное представление, которое будет передавать данные в целевую таблицу, будет выглядеть так:
Таблица с годовой агрегацией и материализованное представление
Теперь мы создадим второе материализованное представление, которое будет связано с нашей ранее созданной целевой таблицей monthly_aggregated_data.
Сначала мы создадим новую целевую таблицу, которая будет хранить суммарное количество просмотров, агрегированное по годам для каждого доменного имени.
Этот шаг определяет каскад. Оператор FROM будет использовать таблицу monthly_aggregated_data, это означает, что поток данных будет следующим:
- Данные поступают в таблицу
hourly_data. - ClickHouse перенаправит полученные данные в первую таблицу материализованного представления —
monthly_aggregated_data. - Наконец, данные, полученные на шаге 2, будут перенаправлены в таблицу
year_aggregated_data.
Распространённое заблуждение при работе с материализованными представлениями (Materialized views) состоит в том, что данные читаются из таблицы. На самом деле Materialized views работают иначе: пересылаются вставляемые блоки, а не конечный результат в вашей таблице.
Представим, что в этом примере в monthly_aggregated_data используется движок CollapsingMergeTree. Тогда данные, пересылаемые во второе материализованное представление year_aggregated_data_mv, не будут итоговым результатом уже «схлопнутой» таблицы; будет переслан блок данных с полями, определёнными в запросе SELECT ... GROUP BY.
Если вы используете CollapsingMergeTree, ReplacingMergeTree или SummingMergeTree и планируете создать каскад материализованных представлений, вам необходимо понимать описанные здесь ограничения.
Пример данных
Теперь можно протестировать наше каскадное материализованное представление, вставив некоторые данные:
Если выполнить SELECT из analytics.hourly_data, вы увидите следующее: движок таблицы — Null, но данные при этом были обработаны.
Мы использовали небольшой набор данных, чтобы убедиться, что можем отслеживать и сравнивать результаты с ожидаемыми. Когда ваш конвейер корректно работает с небольшим набором данных, вы можете перейти к большому объёму данных.
Результаты
Если вы попытаетесь выполнить запрос к целевой таблице, выбрав поле sumCountViews, вы увидите его двоичное представление (в некоторых терминалах), так как значение хранится не как число, а как тип данных AggregateFunction.
Чтобы получить конечный результат агрегации, используйте суффикс -Merge.
Вы можете увидеть специальные символы, хранящиеся в AggregateFunction, с помощью этого запроса:
Вместо этого попробуем использовать суффикс Merge, чтобы получить значение sumCountViews:
В AggregatingMergeTree мы определили AggregateFunction как sum, поэтому можем использовать sumMerge. Если мы используем функцию avg для AggregateFunction, то используем avgMerge и так далее.
Теперь мы можем убедиться, что материализованные представления соответствуют поставленной задаче.
Теперь, когда данные сохранены в целевой таблице monthly_aggregated_data, мы можем получить агрегированные по месяцам данные для каждого доменного имени:
Агрегированные по годам данные для каждого доменного имени:
Объединение нескольких исходных таблиц в одну целевую таблицу
Материализованные представления также можно использовать для объединения нескольких исходных таблиц в одну и ту же целевую таблицу. Это полезно для создания материализованного представления, которое работает аналогично логике UNION ALL.
Сначала создайте две исходные таблицы, представляющие разные наборы метрик:
Затем создайте таблицу Target с объединённым набором метрик:
Создайте два материализованных представления, ссылающихся на одну и ту же таблицу Target. Нет необходимости явно перечислять отсутствующие столбцы:
Теперь при вставке значений они будут агрегироваться в соответствующие столбцы таблицы Target:
Объединённые показы и клики в таблице Target:
Этот запрос должен вывести примерно следующее: