Перейти к основному содержанию

Введение

ClickStack может использовать Incremental Materialized Views (IMV), чтобы ускорять визуализации, основанные на запросах с интенсивной агрегацией, например при расчете средней длительности запросов по минутам за определенный период. Эта возможность может значительно повысить производительность запросов и обычно наиболее полезна для крупных развертываний — от 10 ТБ в день и выше, — а также позволяет масштабироваться до объемов в PB в день. Incremental materialized views находятся в статусе бета и должны использоваться с осторожностью.
Оповещения тоже могут выигрывать от materialized views и будут использовать их автоматически. Это может снизить вычислительные затраты на выполнение большого количества оповещений, особенно потому, что они обычно запускаются очень часто. Сокращение времени выполнения положительно сказывается и на отзывчивости, и на потреблении ресурсов.

Что такое incremental materialized views

Incremental materialized views позволяют перенести вычислительные затраты со времени выполнения запроса на момент вставки, что значительно ускоряет запросы SELECT. В отличие от транзакционных баз данных, таких как Postgres, materialized view в ClickHouse — это не сохранённый снимок. Вместо этого она работает как trigger, который выполняет запрос над блоками данных по мере их вставки в исходную таблицу. Результат этого запроса записывается в отдельную целевую таблицу. По мере вставки новых данных в целевую таблицу добавляются новые частичные результаты, которые затем сливаются. Итоговый слитый результат эквивалентен выполнению агрегации по всему исходному набору данных. Основная причина использовать materialized views заключается в том, что данные, записываемые в целевую таблицу, представляют собой результат агрегации, фильтрации или преобразования. В ClickStack они используются исключительно для агрегаций. Эти результаты обычно значительно меньше, чем исходные данные, и часто представляют собой Промежуточные состояния агрегации. В сочетании с простотой запросов к предварительно агрегированной целевой таблице это даёт существенно меньшую задержку по сравнению с выполнением тех же вычислений над сырыми данными во время выполнения запроса. Materialized views в ClickHouse непрерывно обновляются по мере поступления данных в исходную таблицу и больше похожи на всегда актуальные индексы. Это отличается от многих других баз данных, где materialized views представляют собой статические снимки, которые нужно периодически обновлять, как в ClickHouse Refreshable Materialized Views. Incremental materialized views вычисляют только изменения в представлении по мере поступления новых данных, перенося вычисления на момент вставки. Поскольку ClickHouse хорошо оптимизирован для ингестии, дополнительные затраты на поддержку представления для каждого вставленного блока невелики по сравнению с выигрышем при выполнении запросов. Стоимость вычисления агрегации распределяется между операциями вставки, а не оплачивается заново при каждом чтении. Поэтому запросы к предварительно агрегированным результатам обходятся значительно дешевле, чем их повторное вычисление, что снижает эксплуатационные затраты и обеспечивает производительность, близкую к реальному времени, для последующих визуализаций даже в масштабе петабайтов. Эта модель принципиально отличается от систем, которые пересчитывают представления целиком при каждом обновлении или полагаются на обновление по расписанию. Более подробное объяснение того, как работают materialized views и как их создавать, см. в руководстве по ссылке выше. Каждое materialized view создаёт дополнительную нагрузку в момент вставки, поэтому их следует использовать выборочно.
Создавайте представления только для наиболее часто используемых панелей мониторинга и визуализаций. Пока эта возможность находится в статусе бета, ограничьтесь менее чем 20 представлениями. Ожидается, что в будущих релизах этот порог будет увеличен.
Одно materialized view может вычислять несколько метрик для разных группировок, например минимальную, максимальную и p95 длительность для каждого service name в одноминутных бакетах. Это позволяет одному представлению использоваться во множестве визуализаций, а не только в одной. Поэтому важно объединять метрики в общие представления, чтобы максимально повысить ценность каждого представления и обеспечить его повторное использование в панелях мониторинга и рабочих процессах.
Прежде чем двигаться дальше, рекомендуется глубже ознакомиться с materialized views в ClickHouse. Дополнительные сведения см. в нашем руководстве по Incremental materialized views.

Выбор визуализаций для ускорения

Прежде чем создавать какие-либо materialized views, важно понять, какие визуализации вы хотите ускорить и какие сценарии наиболее важны для ваших пользователей. В ClickStack materialized views предназначены для ускорения визуализаций с большим количеством агрегаций, то есть запросов, которые вычисляют одну или несколько метрик во времени. Например, это средняя длительность запросов по минутам, количество запросов по сервисам или частота ошибок во времени. Materialized view всегда должна содержать агрегацию и группировку по времени, поскольку она предназначена для визуализаций временных рядов. В общем случае рекомендуется следующее:

Определите визуализации, где ускорение даст наибольший эффект

Лучшими кандидатами для ускорения обычно являются визуализации из одной из следующих категорий:
  • Визуализации на панелях мониторинга, которые часто обновляются и постоянно отображаются, например сводные панели мониторинга на настенных экранах.
  • Диагностические сценарии из runbook, в которых во время реагирования на инциденты к определённым диаграммам обращаются repeatedly и результаты должны возвращаться быстро.
  • Ключевые сценарии работы в HyperDX, включая:
    • Представления гистограмм на странице Search.
    • Визуализации, используемые в предустановленных панелях мониторинга, таких как APM, Services или Kubernetes.
Такие визуализации часто повторно выполняются разными пользователями и для разных временных диапазонов, поэтому они хорошо подходят для переноса вычислений с этапа выполнения запроса на этап вставки данных.

Соизмеряйте пользу с затратами при вставке

materialized view добавляют дополнительную нагрузку при вставке, поэтому создавать их следует выборочно и осознанно. Не каждая визуализация выигрывает от предварительной агрегации, а ускорение редко используемых графиков обычно не оправдывает накладные расходы. Общее количество materialized view не должно превышать 20.
Перед переходом в продакшн всегда проверяйте дополнительную нагрузку на ресурсы, создаваемую materialized view, особенно загрузку CPU, дисковый I/O и активность слияния. Каждая materialized view увеличивает объём работы при вставке и добавляет новые части, поэтому важно убедиться, что слияния успевают за нагрузкой, а число частей остаётся стабильным. Это можно отслеживать через системные таблицы и встроенную панель мониторинга обсервабилити в open-source ClickHouse или с помощью встроенных метрик и панелей мониторинга в ClickHouse Cloud. Рекомендации по диагностике и устранению чрезмерного числа частей см. в разделе Too many parts.
После того как вы определили наиболее важные визуализации, следующим шагом станет консолидация.

Объединение визуализаций в общие представления

Все materialized view в ClickStack должны группировать данные по временному интервалу с помощью таких функций, как toStartOfMinute. Однако многие визуализации также используют дополнительные ключи группировки, например имя сервиса, имя спана или код статуса. Если несколько визуализаций используют одни и те же измерения для группировки, их часто можно обслужить с помощью одной materialized view. Например (для трассировок):
  • Средняя длительность по имени сервиса с разбивкой по времени - SELECT avg(Duration), toStartOfMinute(Timestamp) as time, ServiceName FROM otel_traces GROUP BY ServiceName, time
  • Количество запросов по имени сервиса с разбивкой по времени - SELECT count() count, toStartOfMinute(Timestamp) as time, ServiceName FROM otel_traces GROUP BY ServiceName, time
  • Средняя длительность по коду статуса с разбивкой по времени - SELECT avg(Duration), toStartOfMinute(Timestamp) as time, StatusCode FROM otel_traces GROUP BY StatusCode, time
  • Количество запросов по коду статуса с разбивкой по времени - SELECT count() count, toStartOfMinute(Timestamp) as time, StatusCode FROM otel_traces GROUP BY StatusCode, time
Вместо того чтобы создавать отдельные materialized view для каждого запроса и графика, вы можете объединить их в одно представление, агрегирующее данные по имени сервиса и коду статуса. Такое единое представление может вычислять несколько метрик, например количество, среднюю длительность, максимальную длительность, а также процентили, которые затем можно повторно использовать в нескольких визуализациях. Ниже показан пример запроса, объединяющего всё вышеперечисленное:
SELECT avg(Duration), max(Duration), count(), quantiles(0.95,0.99)(Duration), toStartOfMinute(Timestamp) as time, ServiceName, StatusCode
FROM otel_traces
GROUP BY time, ServiceName, StatusCode
Объединение представлений таким образом снижает накладные расходы при вставке, ограничивает общее число materialized view, уменьшает проблемы с числом частей и упрощает дальнейшее сопровождение. На этом этапе сосредоточьтесь на запросах, которые будут выполняться визуализациями, работу которых вы хотите ускорить. В следующем разделе вы увидите пример того, как несколько aggregation queries можно объединить в одно materialized view.

Создание materialized view

После того как вы определили визуализацию или набор визуализаций, которые хотите ускорить, следующим шагом будет определить лежащие в их основе запросы. На практике это означает изучить конфигурацию визуализации и просмотреть сгенерированный SQL, обращая особое внимание на используемые метрики агрегации и применяемые функции.
Если в HyperDX для компонента недоступна панель отладки, пользователи могут проверить консоль браузера, где записываются все запросы.
После того как вы соберёте необходимые запросы, вам следует ознакомиться с функциями состояний агрегации в ClickHouse. Materialized views используют эти функции, чтобы перенести вычисления с этапа выполнения запроса на этап вставки. Вместо хранения итоговых агрегированных значений materialized view вычисляет и сохраняет промежуточные состояния агрегации, которые затем объединяются и финализируются во время выполнения запроса. Обычно они значительно меньше исходной таблицы. Для этих состояний существуют специальные типы данных, и они должны быть явно представлены в схеме целевой таблицы. Для справки: в документации ClickHouse приведены подробный обзор и примеры функций состояний агрегации, а также движка таблицы, который используется для их хранения, — AggregatingMergeTree: Ниже вы можете посмотреть пример использования AggregatingMergeTree и агрегатных функций:
Настоятельно рекомендуется ознакомиться с этими концепциями, прежде чем двигаться дальше.

Пример materialized view

Рассмотрим следующий запрос, который вычисляет среднюю и максимальную длительность, количество событий и перцентили за каждую минуту с группировкой по имени сервиса и коду статуса:
SELECT
    toStartOfMinute(Timestamp),
    ServiceName,
    StatusCode,
    count() AS count,
    avg(Duration),
    max(Duration),
    quantiles(0.95, 0.99)(Duration)
FROM otel_traces
GROUP BY
    time,
    ServiceName,
    StatusCode
Чтобы ускорить этот запрос, создайте целевую таблицу otel_traces_1m, в которой будут храниться соответствующие состояния агрегирования:
CREATE TABLE otel_traces_1m
(
    `Timestamp` DateTime,
    `ServiceName` LowCardinality(String),
    `StatusCode` LowCardinality(String),
    `count` SimpleAggregateFunction(sum, UInt64),
    `avg__Duration` AggregateFunction(avg, UInt64),
    `max__Duration` SimpleAggregateFunction(max, Int64),
    `quantiles__Duration` AggregateFunction(quantiles(0.95, 0.99), Int64)
)
ENGINE = AggregatingMergeTree
ORDER BY (Timestamp, ServiceName, StatusCode);
Определение materialized view — otel_traces_1m_mv — затем вычисляет и записывает эти состояния при вставке новых данных:
CREATE MATERIALIZED VIEW otel_traces_1m_mv TO otel_traces_1m
AS
SELECT
    toStartOfMinute(Timestamp) AS Timestamp,
    ServiceName,
    StatusCode,
    count() AS count,
    avgState(Duration) AS avg__Duration,
    maxSimpleState(Duration) AS max__Duration,
    quantilesState(0.95, 0.99)(Duration) AS quantiles__Duration
FROM otel_v2.otel_traces
GROUP BY
    Timestamp,
    ServiceName,
    StatusCode;
Этот materialized view состоит из двух частей:
  1. Целевая таблица, которая определяет схему и типы агрегатных состояний, используемые для хранения промежуточных результатов. Чтобы эти состояния корректно объединялись в фоне, требуется движок AggregatingMergeTree.
  2. Запрос materialized view автоматически выполняется при вставке. По сравнению с исходным запросом он использует функции состояний, такие как avgState и quantilesState, вместо финальных агрегатных функций.
В результате получается компактная таблица, которая хранит поминутные состояния агрегации для каждого имени сервиса и кода статуса. Ее размер предсказуемо растет со временем и с увеличением мощности, а после фоновых слияний она дает тот же результат, что и выполнение исходной агрегации по сырым данным. Запросы к этой таблице значительно дешевле, чем агрегация напрямую по исходной таблице трейсов, что обеспечивает быструю и стабильную работу визуализаций в крупном масштабе.

Использование materialized view в ClickStack

После создания materialized view в ClickHouse их необходимо зарегистрировать в ClickStack, чтобы они автоматически использовались в визуализациях, на панелях мониторинга и в оповещениях.

Регистрация materialized view для использования

materialized view следует регистрировать для источника в HyperDX, который соответствует исходной таблице, из которой было получено это представление.
1

Измените источник

Перейдите к нужному источнику в HyperDX и откройте диалог Edit configuration. Прокрутите страницу до раздела materialized views.
2

Добавьте materialized view

Выберите Add materialized view, затем укажите базу данных и целевую таблицу, на которых основано materialized view.
3

Выберите метрики

В большинстве случаев столбцы временной метки, размерности и метрик будут определены автоматически. Если этого не произошло, укажите их вручную.Для метрик необходимо сопоставить:
  • исходное имя столбца, например Duration, с
  • соответствующим агрегированным столбцом в materialized view, например avg__Duration
Для размерностей укажите все столбцы, кроме временной метки, по которым представление выполняет группировку.
4

Выберите временную гранулярность

Выберите временную гранулярность materialized view, например одну минуту.
5

Выберите минимальную дату

Укажите минимальную дату, начиная с которой materialized view содержит данные. Это самая ранняя временная метка, доступная в представлении, и обычно это время создания представления, если ингестия шла непрерывно.
materialized view не дозагружаются автоматически при создании, поэтому они будут содержать только строки, сформированные из данных, вставленных после создания. Полное руководство по дозагрузке materialized views можно найти в разделе “Дозагрузка данных.”
Если точное время начала неизвестно, его можно определить, выполнив запрос минимальной временной метки из целевой таблицы, например:
SELECT min(Timestamp) FROM otel_traces_1m
6

Сохраните источник

Сохраните конфигурацию источника.
После регистрации materialized view ClickStack будет автоматически использовать его везде, где это применимо к запросу, без необходимости изменять панели мониторинга, визуализации или alerts. ClickStack анализирует каждый запрос во время выполнения и определяет, можно ли применить materialized view.

Проверка ускорения в панелях мониторинга и визуализациях

Важно помнить, что incremental materialized view содержат только данные, вставленные после создания представления. Исторические данные в них автоматически не дозагружаются, что делает их легковесными и недорогими в сопровождении. Поэтому при регистрации представления пользователи должны явно указывать допустимый временной диапазон.
ClickStack будет использовать materialized view, только если её минимальная временная метка меньше или равна началу временного диапазона запроса — это гарантирует, что представление содержит все необходимые данные. Хотя запросы внутри системы разбиваются на подзапросы по времени, materialized view применяются либо ко всему запросу целиком, либо не применяются вовсе. В будущем возможны улучшения, которые позволят использовать представления выборочно для подходящих подзапросов.
ClickStack предоставляет понятные визуальные индикаторы, по которым можно определить, используется ли materialized view.
  1. Проверьте статус оптимизации При просмотре панели мониторинга или визуализации найдите значок молнии или Accelerated:
  • Зелёная молния означает, что запрос ускорен с помощью materialized view.
  • Оранжевая молния означает, что запрос выполняется по исходной таблице.
  1. Изучите сведения об оптимизации Нажмите на значок молнии, чтобы открыть панель с подробностями, где показано:
  • Активное materialized view: представление, выбранное для запроса, включая оценочное количество строк.
  • Пропущенные materialized view: совместимые представления, которые не были выбраны, вместе с оценочным объёмом сканирования.
  • Несовместимые materialized view: представления, которые не удалось использовать, и конкретная причина.
  1. Разберитесь в распространённых причинах несовместимости Materialized view может не использоваться, если:
  • Временной диапазон запроса начинается раньше минимальной временной метки представления.
  • Гранулярность визуализации не кратна гранулярности представления.
  • Функция агрегации, запрошенная в запросе, отсутствует в представлении.
  • В запросе используются пользовательские выражения count, например count(if(...)), которые нельзя получить из состояний агрегации представления.
Эти индикаторы позволяют легко проверить, ускорена ли визуализация, понять, почему было выбрано конкретное представление, и выяснить, почему представление не подошло.

Как materialized views выбираются для визуализаций

При выполнении визуализации у ClickStack может быть несколько возможных вариантов, включая базовую таблицу и несколько materialized views. Чтобы обеспечить оптимальную производительность, ClickStack автоматически оценивает и выбирает наиболее эффективный вариант с помощью механизма ClickHouse EXPLAIN ESTIMATE. Процесс выбора проходит по четко определенной последовательности:
  1. Проверка совместимости Сначала ClickStack определяет, подходит ли materialized view для запроса, проверяя:
    • Покрытие по времени: временной диапазон запроса должен полностью попадать в доступный диапазон данных materialized view.
    • Гранулярность: временной бакет визуализации должен быть равен гранулярности view или быть более грубым.
    • Агрегации: запрошенные метрики должны присутствовать во view и вычисляться из их состояний агрегации.
  2. Преобразование запроса Для совместимых view ClickStack переписывает запрос так, чтобы он обращался к таблице materialized view:
    • Функции агрегации сопоставляются с соответствующими материализованными столбцами.
    • К состояниям агрегации применяются комбинаторы -Merge.
    • Группировка по времени корректируется в соответствии с гранулярностью view.
  3. Выбор лучшего кандидата Если доступно несколько совместимых materialized views, ClickStack выполняет запрос EXPLAIN ESTIMATE для каждого кандидата и сравнивает расчетное число просканированных строк и гранул. Выбирается view с наименьшей расчетной стоимостью сканирования.
  4. Плавный fallback Если ни один materialized view не подходит, ClickStack автоматически возвращается к запросу исходной таблицы.
Такой подход стабильно минимизирует объем сканируемых данных и обеспечивает предсказуемую производительность с низкой задержкой без необходимости изменять определения визуализаций. Materialized views остаются применимыми даже в тех случаях, когда визуализации включают фильтры, поисковые ограничения или группировку по времени, при условии, что во view присутствуют все необходимые измерения. Это позволяет view ускорять панели мониторинга, гистограммы и отфильтрованные графики без необходимости изменять определения визуализаций.

Пример выбора materialized views

Рассмотрим два materialized views, созданных для одного и того же источника трассировки:
  • otel_traces_1m, сгруппированное по минутам, ServiceName и StatusCode
  • otel_traces_1m_v2, сгруппированное по минутам, ServiceName, StatusCode и SpanName
Второе представление содержит дополнительные ключи группировки и поэтому создает больше строк и сканирует больше данных. Если визуализация запрашивает среднюю длительность по сервисам во времени, оба представления технически подходят. ClickStack выполняет запрос EXPLAIN ESTIMATE для каждого кандидата и сравнивает оценочное количество гранул, то есть:
EXPLAIN ESTIMATE
SELECT
    toStartOfHour(Timestamp) AS hour,
    ServiceName,
    avgMerge(avg__Duration) AS avg__Duration
FROM otel_v2.otel_traces_1m
GROUP BY
    hour,
    ServiceName
ORDER BY hour DESC
┌─database─┬─table──────────┬─parts─┬──rows─┬─marks─┐
│ otel_v2  │ otel_traces_1m │     1 │ 49385 │     6 │
└──────────┴────────────────┴───────┴───────┴───────┘

1 row in set. Elapsed: 0.009 sec.
EXPLAIN ESTIMATE
SELECT
    toStartOfHour(Timestamp) AS hour,
    ServiceName,
    avgMerge(avg__Duration) AS avg__Duration
FROM otel_v2.otel_traces_1m_v2
GROUP BY
    hour,
    ServiceName
ORDER BY hour DESC
┌─database─┬─table─────────────┬─parts─┬───rows─┬─marks─┐
│ otel_v2  │ otel_traces_1m_v2 │     1 │ 212519 │    26 │
└──────────┴───────────────────┴───────┴────────┴───────┘

1 row in set. Elapsed: 0.004 sec.
Поскольку otel_traces_1m меньше и сканирует меньше гранул, она выбирается автоматически. Обе materialized view по-прежнему работают быстрее, чем запросы напрямую к базовой таблице, но выбор наименьшего подходящего представления обеспечивает наилучшую производительность.

Оповещения

Если это возможно, запросы оповещений автоматически используют materialized views. Используется та же логика оптимизации, что ускоряет оценку оповещений.

Дозагрузка materialized view

Как отмечалось ранее, incremental materialized view содержат только данные, вставленные после создания представления, и не дозагружаются историческими данными автоматически. Такой подход делает представления лёгкими и недорогими в эксплуатации, но также означает, что их нельзя использовать для запросов, которым нужны данные с временными метками раньше минимальной временной метки представления. В большинстве случаев это приемлемо. Типичные рабочие нагрузки ClickStack сосредоточены на свежих данных, например за последние 24 часа, а значит, новое представление становится полностью пригодным к использованию в течение суток после создания. Однако для запросов, охватывающих более длинные временные диапазоны, представление может оставаться непригодным к использованию, пока не пройдёт достаточно времени. В таких случаях пользователи могут рассмотреть дозагрузку materialized view историческими данными. Дозагрузка может быть вычислительно затратной. При нормальной работе materialized view заполняются инкрементально по мере поступления данных, равномерно распределяя вычислительные затраты во времени. При дозагрузке эта работа сжимается в гораздо более короткий период, что значительно увеличивает нагрузку на CPU и использование памяти в единицу времени. В зависимости от размера датасета и окна хранения данных это может потребовать временного масштабирования кластера — вертикального или, в ClickHouse Cloud, горизонтального — чтобы завершить дозагрузку в разумные сроки. Если дополнительные ресурсы не выделены, дозагрузка может негативно повлиять на рабочие нагрузки в продакшн, включая задержку запросов и пропускную способность ингестии. Для очень больших датасетов или длинных исторических диапазонов дозагрузка может оказаться непрактичной или вовсе невыполнимой. Итог: во многих случаях дозагрузка не оправдывает ни затрат, ни операционных рисков. Рассматривать её стоит только в исключительных ситуациях, когда ускорение работы с историческими данными критически важно. Если вы всё же решите продолжить, рекомендуется следовать описанному ниже контролируемому подходу, чтобы сбалансировать производительность, стоимость и влияние на продакшн.

Подходы к дозагрузке

Избегайте POPULATEИспользовать команду POPULATE для дозагрузки materialized view не рекомендуется, за исключением небольших наборов данных, когда приём приостановлен. Этот оператор может пропускать строки, вставленные в исходную таблицу, поскольку materialized view создаётся только после завершения POPULATE. Кроме того, POPULATE выполняется по всем данным и на больших наборах данных подвержен сбоям из-за прерываний или ограничений памяти.
Предположим, вы хотите выполнить дозагрузку materialized view, соответствующего следующей агрегации, которая вычисляет поминутные метрики, сгруппированные по имени сервиса и коду состояния:
SELECT
    toStartOfMinute(Timestamp),
    ServiceName,
    StatusCode,
    count() AS count,
    avg(Duration),
    max(Duration),
    quantiles(0.95, 0.99)(Duration)
FROM otel_traces
GROUP BY
    time,
    ServiceName,
    StatusCode
Как обсуждалось ранее, incremental materialized views не дозагружаются автоматически. Ниже приведены рекомендуемые способы безопасной дозагрузки исторических данных с сохранением инкрементного поведения для новых данных.

Прямая дозагрузка с помощью INSERT INTO SELECT

Этот подход лучше всего подходит для небольших наборов данных или относительно нетяжёлых запросов на агрегацию, когда полную дозагрузку можно выполнить за разумное время без исчерпания ресурсов кластера. Обычно он уместен, когда запрос дозагрузки выполняется за минуты или максимум за несколько часов, а временное увеличение нагрузки на CPU и I/O допустимо. Для более крупных наборов данных или более ресурсоёмких агрегаций вместо этого рассмотрите описанные ниже инкрементальный или блочный подходы к дозагрузке.
1
Определите текущее покрытие представления
Прежде чем выполнять дозагрузку, сначала определите, какие данные уже содержит materialized view. Для этого выполните запрос, возвращающий минимальную временную метку в целевой таблице:
SELECT min(Timestamp)
FROM otel_traces_1m;
Эта временная метка представляет самую раннюю точку, начиная с которой представление может обслуживать запросы. Любой запрос из ClickStack, запрашивающий данные раньше этой временной метки, будет обращаться к базовой таблице.
2
Решите, нужна ли дозагрузка
В большинстве развертываний ClickStack запросы сосредоточены на недавних данных, например за последние 24 часа. В таких случаях вновь созданные представления становятся полностью пригодными к использованию вскоре после создания, и дозагрузка не требуется.Если временная метка, полученная на предыдущем шаге, достаточно ранняя для ваших сценариев использования, дозагрузка не нужна. Рассматривать дозагрузку следует только в следующих случаях:
  • Запросы часто охватывают длинные исторические диапазоны.
  • Представление критично для производительности на этих диапазонах.
  • Размер набора данных и стоимость агрегации делают дозагрузку целесообразной.
3
Дозагрузите отсутствующие исторические данные
Если дозагрузка необходима, заполните целевую таблицу materialized view для временных меток раньше текущего минимума, используя запрос из представления, изменённый так, чтобы он читал только данные старше временной метки, зафиксированной выше. Поскольку целевая таблица использует AggregatingMergeTree, запрос дозагрузки должен вставлять состояния агрегации, а не итоговые значения.
Этот запрос может обрабатывать большие объёмы данных и требовать значительных ресурсов. Перед запуском дозагрузки всегда проверяйте доступную ёмкость CPU, памяти и I/O. Полезный приём — сначала выполнить запрос с FORMAT Null, чтобы оценить время выполнения и потребление ресурсов.Если ожидается, что сам запрос будет выполняться много часов, этот подход не рекомендуется.
Обратите внимание, что следующий запрос добавляет условие WHERE, чтобы ограничить агрегацию данными старше самой ранней временной метки, присутствующей в представлении:
INSERT INTO otel_traces_1m
SELECT
    toStartOfMinute(Timestamp) AS Timestamp,
    ServiceName,
    StatusCode,
    count() AS count,
    avgState(Duration) AS avg__Duration,
    maxSimpleState(Duration) AS max__Duration,
    quantilesState(0.95, 0.99)(Duration) AS quantiles__Duration
FROM otel_traces
WHERE Timestamp < (
    SELECT min(Timestamp) FROM otel_traces_1m
)
GROUP BY
    Timestamp,
    ServiceName,
    StatusCode;

Инкрементальная дозагрузка с использованием таблицы Null

Для более крупных наборов данных или более ресурсоёмких запросов на агрегацию прямая дозагрузка с помощью одного INSERT INTO SELECT может быть непрактичной или небезопасной. В таких случаях рекомендуется подход инкрементальной дозагрузки. Этот метод точнее воспроизводит обычную работу incremental materialized views: данные обрабатываются управляемыми блоками, а не агрегируются сразу по всему историческому набору данных. Этот подход подходит, когда:
  • Иначе запрос дозагрузки выполнялся бы много часов.
  • Пиковое потребление памяти при полной агрегации слишком велико.
  • Вы хотите жёстко контролировать потребление CPU и памяти во время дозагрузки.
  • Вам нужен более устойчивый процесс, который можно безопасно перезапустить в случае прерывания.
Ключевая идея состоит в использовании таблицы Null в качестве буфера ингестии. Хотя таблица Null не хранит данные, все materialized views, прикреплённые к ней, всё равно будут выполняться, что позволяет инкрементально вычислять состояния агрегации по мере прохождения данных через неё.
1
Создайте таблицу Null для дозагрузки
Создайте лёгкую таблицу Null, содержащую только те столбцы, которые нужны для агрегации в materialized view. Это минимизирует I/O и использование памяти.
CREATE TABLE otel_traces_backfill
(
    Timestamp DateTime64(9),
    ServiceName LowCardinality(String),
    StatusCode LowCardinality(String),
    Duration UInt64
)
ENGINE = Null;
2
Прикрепите materialized view к таблице Null
Затем создайте materialized view для таблицы Null, направленную в ту же таблицу агрегации, что и ваша основная materialized view.
CREATE MATERIALIZED VIEW otel_traces_1m_mv_backfill
TO otel_traces_1m
AS
SELECT
    toStartOfMinute(Timestamp) AS Timestamp,
    ServiceName,
    StatusCode,
    count() AS count,
    avgState(Duration) AS avg__Duration,
    maxSimpleState(Duration) AS max__Duration,
    quantilesState(0.95, 0.99)(Duration) AS quantiles__Duration
FROM otel_traces_backfill
GROUP BY
    Timestamp,
    ServiceName,
    StatusCode;
Эта materialized view будет выполняться инкрементально по мере вставки строк в таблицу Null, формируя состояния агрегации небольшими блоками.
3
Выполните инкрементальную дозагрузку данных
Наконец, вставьте исторические данные в таблицу Null. Materialized view будет обрабатывать данные блок за блоком, передавая состояния агрегации в целевую таблицу без сохранения исходных строк.
INSERT INTO otel_traces_backfill
SELECT
    Timestamp,
    ServiceName,
    StatusCode,
    Duration
FROM otel_traces
WHERE Timestamp < (
    SELECT min(Timestamp) FROM otel_traces_1m
);
Поскольку данные обрабатываются инкрементально, использование памяти остаётся ограниченным и предсказуемым, что очень похоже на обычное поведение ингестии.
Для дополнительной безопасности рассмотрите возможность направить materialized view для дозагрузки во временную целевую таблицу (например, otel_traces_1m_v2). После успешного завершения дозагрузки партиции можно переместить в основную целевую таблицу, например: ALTER TABLE otel_traces_1m_v2 MOVE PARTITION '2026-01-02' TO otel_traces_1m. Это позволит легко восстановиться, если дозагрузка будет прервана или завершится ошибкой из-за ограничений ресурсов.
Дополнительные сведения о настройке этого процесса, включая повышение производительности вставки, а также снижение и контроль потребления ресурсов, см. в разделе “Дозагрузка.”

Рекомендации

Ниже приведены рекомендации, обобщающие лучшие практики по проектированию и эксплуатации materialized views в ClickStack. Следование этим рекомендациям поможет сделать materialized views эффективными, предсказуемыми и экономичными.

Выбор и согласование гранулярности

Materialized views используются только тогда, когда гранулярность визуализации или оповещения является точным кратным гранулярности представления. То, как определяется эта гранулярность, зависит от типа диаграммы:
  • Временные диаграммы (линейные или столбчатые диаграммы со временем по оси x): Явно заданная гранулярность диаграммы должна быть кратна гранулярности materialized view. Например, диаграмма с 10-минутной гранулярностью может использовать materialized views с гранулярностью 10, 5, 2 или 1 минута, но не представления с гранулярностью 20 или 3 минуты.
  • Диаграммы без временной оси (числовые, табличные или сводные диаграммы): Эффективная гранулярность вычисляется как (time range / 80) с округлением вверх до ближайшей гранулярности, поддерживаемой HyperDX. Эта вычисленная гранулярность также должна быть кратна гранулярности materialized view.
Из-за этих правил:
  • Не создавайте materialized views с 10-минутной гранулярностью. ClickStack поддерживает 15-минутную гранулярность для диаграмм и оповещений, но не 10-минутную. Поэтому materialized view с 10-минутной гранулярностью будет несовместимо с распространёнными 15-минутными визуализациями и оповещениями.
  • Предпочтительнее гранулярность 1 минута или 1 час, так как она хорошо сочетается с большинством конфигураций диаграмм и оповещений.
Более высокая гранулярность (например, 1 час) даёт представления меньшего размера и снижает затраты хранилища, тогда как более низкая гранулярность (например, 1 минута) обеспечивает большую гибкость для детализированного анализа. Выбирайте наименьшую гранулярность, которая подходит для ваших критически важных сценариев.

Ограничивайте количество и объединяйте materialized view

Каждое materialized view создает дополнительную нагрузку при вставке и усиливает нагрузку на parts и merge. Рекомендуется следующее:
  • Не более 20 materialized views на источник.
  • Около 10 materialized views обычно является оптимальным вариантом.
  • Объединяйте несколько визуализаций в одно view, если у них общие измерения.
По возможности вычисляйте несколько метрик и поддерживайте несколько диаграмм на основе одного и того же materialized view.

Тщательно выбирайте измерения

Включайте только те измерения, которые обычно используются для группировки или фильтрации:
  • Каждый дополнительный столбец группировки увеличивает размер представления.
  • Балансируйте гибкость запросов и затраты на хранилище и вставку.
  • Фильтры по столбцам, которых нет в представлении, приведут к тому, что ClickStack будет обращаться к исходной таблице.
СоветРаспространённый и почти всегда полезный базовый вариант — materialized view, сгруппированное по имени сервиса с метрикой count. Это позволяет быстро строить гистограммы и получать обзоры по сервисам в Search и на панелях мониторинга.

Соглашения об именовании столбцов агрегации

Столбцы агрегации в materialized view должны следовать строгому соглашению об именовании, чтобы обеспечить автоматическое определение:
  • Шаблон: <aggFn>__<sourceColumn>
  • Примеры:
    • avg__Duration
    • max__Duration
    • count__ для подсчёта строк
ClickStack использует это соглашение, чтобы корректно сопоставлять запросы со столбцами materialized view.

Квантили и выбор скетча

У разных функций для вычисления квантилей разные характеристики производительности и хранения:
  • quantiles создает на диске более крупные скетчи, но их вычисление во время вставки обходится дешевле.
  • quantileTDigest дороже в вычислении во время вставки, но создает меньшие скетчи, что часто ускоряет запросы к представлениям.
Для обеих функций можно указать размер скетча (например, quantile(0.5) во время вставки. Получившийся скетч затем можно использовать в запросах и для других значений квантилей, например quantile(0.95). Рекомендуется поэкспериментировать, чтобы найти оптимальный баланс для вашей рабочей нагрузки.

Непрерывно проверяйте эффективность

Всегда проверяйте, что materialized views действительно дают ощутимую пользу:
  • Проверяйте их использование по индикаторам ускорения в интерфейсе.
  • Сравнивайте производительность запросов до и после включения представления.
  • Отслеживайте потребление ресурсов и поведение при слиянии.
Materialized views следует рассматривать как оптимизацию производительности, которая требует периодического пересмотра и корректировки по мере изменения шаблонов запросов.

Расширенные конфигурации

Для более сложных рабочих нагрузок можно использовать несколько materialized views, чтобы поддерживать разные сценарии доступа к данным. Примеры:
  • Недавние данные с высоким разрешением и укрупненные исторические представления
  • Представления на уровне сервиса для общего обзора и представления на уровне конечных точек для углубленной диагностики
При выборочном применении такие шаблоны могут значительно повысить производительность, но внедрять их следует только после проверки более простых конфигураций. Соблюдение этих рекомендаций поможет сохранить materialized views эффективными, удобными в сопровождении и согласованными с моделью выполнения ClickStack.

Ограничения

Распространённые причины несовместимости

Materialized view не будет использоваться, если выполняется любое из следующих условий:
  • Временной диапазон запроса Начало временного диапазона запроса приходится на момент раньше минимальной временной метки materialized view. Поскольку materialized view не дозагружаются автоматически, они могут обслуживать только те запросы для временных диапазонов, которые покрывают полностью.
  • Несоответствие гранулярности Эффективная гранулярность визуализации должна быть точным кратным гранулярности materialized view. В частности:
    • Для временных диаграмм (линейных или столбчатых диаграмм со временем по оси x) выбранная гранулярность диаграммы должна быть кратна гранулярности представления. Например, диаграмма с шагом 10 минут может использовать materialized view с шагом 10, 5, 2 или 1 минута, но не с шагом 20 минут или 3 минуты.
    • Для диаграмм без временной оси (числовых или табличных диаграмм) эффективная гранулярность вычисляется как (time range / 80), округляется вверх до ближайшей гранулярности, поддерживаемой HyperDX, и также должна быть кратна гранулярности представления.
  • Неподдерживаемые функции агрегации В запросе используется агрегация, которой нет в materialized view. Можно использовать только те агрегации, которые явно вычислены и сохранены в представлении.
  • Пользовательские выражения count Запросы, использующие выражения вроде count(if(...)) или другие условные подсчёты, нельзя вывести из стандартных состояний агрегации, поэтому они не могут использовать materialized view.

Ограничения проектирования и эксплуатации

  • Без автоматической дозагрузки Incremental materialized view содержат только данные, вставленные после их создания. Для ускорения запросов по историческим данным требуется явная дозагрузка, которая может оказаться дорогой или непрактичной для больших объёмов данных.
  • компромиссы гранулярности Представления с очень высокой гранулярностью увеличивают объём хранилища и накладные расходы при вставке, тогда как более грубая гранулярность снижает гибкость. Гранулярность нужно тщательно подбирать в соответствии с ожидаемыми шаблонами запросов.
  • взрывной рост размерностей Добавление большого числа размерностей группировки существенно увеличивает размер представления и может снизить его эффективность. В представления следует включать только часто используемые столбцы для группировки и фильтрации.
  • ограниченная масштабируемость числа представлений Каждое materialized view добавляет накладные расходы при вставке и усиливает merge pressure. Создание слишком большого числа представлений может негативно повлиять на ингестию и фоновые слияния.
Понимание этих ограничений помогает применять materialized view там, где они действительно приносят пользу, и избегать конфигураций, которые незаметно возвращаются к более медленным запросам к исходной таблице.

Устранение неполадок

Materialized view не используется

Проверка 1: диапазон дат
  • Откройте модальное окно оптимизации и проверьте, отображается ли сообщение “Date range not supported.”
  • Убедитесь, что диапазон дат в запросе начинается после минимальной даты materialized view.
  • Удалите минимальную дату, если materialized view содержит все исторические данные.
Проверка 2: гранулярность
  • Убедитесь, что гранулярность графика кратна гранулярности MV.
  • Попробуйте установить для графика значение “Auto” или вручную выбрать совместимую гранулярность.
Проверка 3: агрегации
  • Проверьте, использует ли график агрегации, присутствующие в MV.
  • Просмотрите раздел “Available aggregated columns” в модальном окне оптимизации.
Проверка 4: измерения
  • Убедитесь, что столбцы группировки входят в список столбцов измерений MV.
  • Проверьте раздел “Available group/filter columns” в модальном окне оптимизации.

Медленные запросы к materialized view

Проблема 1: слишком мелкая гранулярность materialized view
  • В MV слишком много строк из-за слишком мелкой гранулярности (например, 1 секунда).
  • Решение: создайте MV с более грубой гранулярностью (например, 1 минута или 1 час).
Проблема 2: слишком много измерений
  • MV имеет высокую мощность из-за большого количества столбцов измерений.
  • Решение: сократите число столбцов измерений до наиболее часто используемых.
Проблема 3: несколько MV с большим количеством строк
  • Система выполняет EXPLAIN для каждого MV.
  • Решение: удалите MV, которые используются редко или постоянно пропускаются.

Ошибки конфигурации

Ошибка: “Требуется хотя бы один агрегированный столбец”
  • Добавьте в конфигурацию MV хотя бы один агрегированный столбец.
Ошибка: “Для агрегаций, отличных от count, требуется столбец-источник”
  • Укажите, какой столбец нужно агрегировать (только для count столбец-источник можно не указывать).
Ошибка: “Недопустимый формат гранулярности”
  • Используйте одно из предустановленных значений гранулярности в выпадающем списке.
  • Формат должен быть корректным SQL-интервалом (например, 1 hour, а не 1 h).
Последнее изменение 10 июня 2026 г.