В этом руководстве показано, как поддерживать предварительно агрегированные rollup-данные из высоконагруженной таблицы событий с помощью materialized views. Вы создадите три объекта: сырую таблицу, таблицу rollup и materialized view, которая автоматически записывает данные в rollup.
Когда использовать этот шаблон
- У вас есть поток событий, в который данные только добавляются (клики, просмотры страниц, IoT, журналы).
- Большинство запросов — это агрегации по временным диапазонам (по минутам/часам/дням).
- Вам нужно стабильное чтение данных менее чем за секунду без повторного сканирования всех необработанных строк.
1
Создайте таблицу сырых событий
PARTITION BY toYYYYMM(event_time)разбивает данные на небольшие партиции, которые легко удалять.ORDER BY (event_time, user_id)оптимизирует запросы с ограничением по времени и дополнительной фильтрацией.LowCardinality(String)экономит память для категориальных измерений.TTLудаляет необработанные данные через 90 дней (настройте в соответствии с вашими требованиями к сроку хранения).
2
Спроектируйте rollup-таблицу (агрегированную таблицу)
Мы будем выполнять предварительную агрегацию с часовой детализацией. Выбирайте уровень детализации под наиболее типичный временной диапазон анализа.AggregateFunction(sum, ...)), которые компактно представляют частичные агрегаты и впоследствии могут быть объединены или финализированы.3
Создайте materialized view, заполняющее rollup
Это materialized view автоматически срабатывает при вставке вevents_raw и записывает состояния агрегатных функций в rollup.4
5
Выполнение запросов к rollup
Вы можете либо объединять состояния при чтении, либо финализировать их:- Объединение при чтении
- Финализация с -Final
6
Фильтруйте по полям первичного ключа для наилучшей производительности
Чтобы увидеть, как индекс отсекает данные, можно использовать командуEXPLAIN:Query
Response
(bucket_start, country, event_type).
Чтобы обеспечить максимальную эффективность фильтрации, убедитесь, что ваши запросы используют поля первичного ключа для отсечения данных.7
Распространённые варианты
- Разная гранулярность: добавьте ежедневную агрегацию:
- Сжатие: применяйте кодеки к большим столбцам (например,
Codec(ZSTD(3))) в raw-таблице. - Контроль затрат: основную нагрузку по хранению возложите на raw-таблицу, а roll-up’ы храните долго.
- Дозагрузка: при загрузке исторических данных вставляйте их в
events_raw, а materialized view автоматически построит roll-up’ы. Для существующих строк используйтеPOPULATEпри создании materialized view, если это уместно, либоINSERT SELECT.
8
Очистка и сроки хранения
- Увеличьте TTL для сырых данных (например, до 30/90 дней), но храните roll-up-данные дольше (например, 1 год).
- Вы также можете использовать TTL для перемещения старых частей в более дешёвое хранилище, если включено распределение по уровням хранения.
9
Устранение неполадок
- materialized view не обновляется? Проверьте, что вставка идет в events_raw (а не в таблицу rollup) и что целевая таблица materialized view указана правильно (
TO events_rollup_1h). - Медленные запросы? Убедитесь, что они обращаются к rollup (выполните запрос к таблице rollup напрямую) и что временные фильтры соответствуют гранулярности rollup.
- Несоответствия при дозагрузке? Используйте
SYSTEM FLUSH LOGSи проверьтеsystem.query_log/system.parts, чтобы подтвердить вставки и слияния.