Недавно я работал над добавлением в материализованные представления StarRocks поддержки нескольких выражений , поэтому подробно разобрал весь путь — от создания MV до его обновления (refresh).

Создание материализованного представления

Пример:

CREATE
MATERIALIZED VIEW mv_test99
REFRESH ASYNC EVERY(INTERVAL 60 MINUTE)
PARTITION BY p_time
PROPERTIES (
  "partition_refresh_number" = "1"
)
AS
select date_trunc("day", a.datekey) as p_time, sum(a.v1) as value
from par_tbl1 a
group by p_time, a.item_id;

На этапе парсинга и анализа вызывается:com.starrocks.sql.analyzer.MaterializedViewAnalyzer.MaterializedViewAnalyzerVisitor#visitCreateMaterializedViewStatemen

Эта процедура преобразует оператор создания в объект CreateMaterializedViewStatement (используется ANTLR) и выполняет семантический анализ и базовые проверки, в том числе:

  • корректность выражения партиционирования;

  • корректность ссылок на базовые таблицы и базы данных;

  • согласованность схемы выходных столбцов и свойств MV.

Далее управление переходит в:com.starrocks.server.LocalMetastore#createMaterializedView()

Ключевые задачи этого этапа:

  • Проверка существования целевой базы данных и одноименного MV.

  • Инициализация базовой информации MV:

    • построение схемы столбцов (schema);

    • валидация схемы;

    • инициализация свойств, включая партиционирование.

  • Настройка стратегии обновления:

    • выбор режима (ASYNC, SYNC, MANUAL, INCREMENTAL);

    • для асинхронного режима — установка интервала, времени начала и валидация параметров.

  • Создание объекта MV:

    • выбор типа в зависимости от режима развертывания (разделение хранения и вычислений или интегрированный режим);

    • настройка индексов, сортировочных ключей, комментариев, привязка базовых таблиц.

  • Партиционирование:

    • для непартиционированного MV — создание единственной партиции и ее свойств;

    • для партиционированного MV — разбор выражения партиционирования и построение соответствия партиций.

  • Привязка тома хранения:

    • для cloud‑native MV — привязка storage volume.

Сериализация ключевых данных

Часть сведений должна переживать перезапуск FE, чтобы при повторной загрузке быть доступной механизмам refresh и анализа. Поэтому ключевые поля сериализуются в метаданные, которые периодически сохраняются в директории fe/meta.

Типичные выносимые в метаданные артефакты:

  • исходный SQL создания MV;

  • выражения партиционирования и их сопоставления;

  • сервисные свойства, влияющие на refresh.

Поля помечаются аннотацией @SerializedName, например:

@SerializedName(value = "partitionExprMaps")
private Map<ExpressionSerializedObject, ExpressionSerializedObject> serializedPartitionExprMaps;

Собственно преобразование выполняется в:

  • com.starrocks.catalog.MaterializedView#gsonPreProcess

  • com.starrocks.catalog.MaterializedView#gsonPostProcess

Синхронизация и загрузка метаданных

В кластере FE лидер периодически создает снимки метаданных:

  • поток checkpoint (checkpoint) решает, когда нужно формировать новый image.${JournalId} (image) — обычно при достижении порога по количеству событий в журнале изменений (edit log), по умолчанию 50 000;

  • метаданные пишутся и читаются согласованно всеми FE (leader/follower).

Упрощенно процесс выглядит так:

  1. Проверка необходимости формирования нового image.

  2. Загрузка метаданных из текущего image в память.

  3. Чтение последних журналов (Journal) из bdb и их replay поверх загруженного состояния.

  4. Генерация нового image из актуального состояния в памяти.

  5. Очистка старых image.

  6. Уведомление follower‑узлов FE о новом image с последующей синхронизацией.

Обновление MV (refresh)

Сразу после успешного создания MV инициируется первичное обновление. Далее обновления могут запускаться по расписанию (ASYNC EVERY ...), вручную или по событиям в базовых таблицах (подробнее).

Синхронизация партиций

Ключевой шаг каждого refresh — выравнивание партиций MV с партициями базовых таблиц. Для range‑партиционирования основная логика сосредоточена в:

Что делает процедура:

  • Вычисляет разницу партиций между MV и базовыми таблицами в заданном диапазоне.

  • Синхронизирует партиции:

    • удаляет устаревшие партиции MV, которые больше не сопоставляются базовым таблицам;

    • добавляет недостающие партиции.

После синхронизации рассчитывается подмножество партиций, подлежащих обновлению в этой итерации. По умолчанию MV обновляет ограниченное число партиций за запуск; параметр:

  • "partition_refresh_number" — задает размер партии. Оставшиеся партиции будут поставлены на последующие запуски, формируя «хвост» заданий до полного охвата диапазона.

Поддержка нескольких выражений в UNION и VirtualPartitions (PR #60035)

Практическая проблема, решенная в [1]: если в определении MV используется UNION ALL с выражениями сдвига дат (date_add/date_sub), обычного сопоставления партиций может быть недостаточно. Например:

CREATE MATERIALIZED VIEW mv_test99
REFRESH ASYNC EVERY(INTERVAL 60 MINUTE)
PARTITION BY p_time
PROPERTIES ("partition_refresh_number" = "1")
AS
select date_trunc('day', a.datekey) as p_time, sum(a.v1) as value
from par_tbl1 a
group by p_time, a.item_id
union all
select date_trunc('day', date_add(b.datekey, INTERVAL 1 DAY)) as p_time, sum(b.v1) as value
from par_tbl1 b
group by p_time, item_id;

Без дополнительной логики одна из партиций может не обновиться, так как новая «производная» дата выходит за рамки партиций, вычисленных напрямую из базовой таблицы. В реальном кейсе отсутствовала партиция p20250103_20250104.

Решение в [1]:

  • При создании MV, если встречается UnionRelation, сохраняются выражения выходных столбцов UNION для последующего вычисления «виртуальных партиций» (VirtualPartitions).

  • При refresh ранее сохраненные VirtualPartitions добавляются к набору партиций, подлежащих обновлению в текущем проходе.

  • VirtualPartitions — это партиции, «выведенные» из партиций базовой таблицы с применением выражений времени (date_add/date_sub). Они:

    • используются только в контексте refresh MV;

    • не меняют схему MV и не влияют на базовую таблицу;

    • позволяют «догружать» смежные диапазоны, которые появляются из‑за сдвигов дат в UNION ALL.

Таким образом, MV корректно обновляется даже при наличии нескольких выражений в UNION ALL, и «выпадающие» партиции больше не теряются.

Примечание по другим сценариям:

  • Для inner join результат — пересечение, добавление date_add на правой стороне обычно не влияет на множество целевых партиций.

  • Для left join результат определяется левой таблицей; добавочные даты справа не расширяют область обновления, поэтому VirtualPartitions обычно не требуются.

  • Концепция VirtualPartitions главным образом востребована для UNION ALL с временными сдвигами; для большинства join‑сценариев стандартной логики достаточно.

Итоги

  • Создание MV проходит через анализ (ANTLR → CreateMaterializedViewStatement), валидацию, инициализацию свойств, настройку refresh и партиционирования.

  • Ключевые метаданные сериализуются и сохраняются в fe/meta; лидер FE периодически формирует image через checkpoint, а изменения фиксируются в edit log.

  • Refresh состоит из синхронизации партиций и порционного обновления выбранных диапазонов (partition_refresh_number).

  • PR [1] добавляет поддержку нескольких выражений в UNION ALL за счет механизма VirtualPartitions, гарантируя, что смещенные датой диапазоны не будут пропущены при обновлении.

Комментарии (1)


  1. PhoenixLi Автор
    25.12.2025 08:06

    [1] Поддержка нескольких выражений: https://github.com/StarRocks/starrocks/pull/60035