-- STG: матвью приёма — из чтеца в сырьё. -- -- Номер 40, а не 11, и пропуск в нумерации намеренный. Файлы 20-ods-tables.sql -- и 30-ods-views.sql приносит #43, и матвью приёма обязана создаваться после -- матвью разбора: Kafka-движок начинает читать топик ровно тогда, когда к нему -- привязывают первую матвью. Создай её раньше разбора — и всё, что доедет в -- зазоре, ляжет в сырьё и не попадёт в ODS никуда, ни в событие, ни в ошибки. -- На пустом топике зазор безвреден, поэтому первый прогон о нём не скажет: -- проснётся он, когда тома ClickHouse снесены, а данные Kafka целы, то есть на -- обычной отладке. Нумерацию здесь не «приводить в порядок». -- -- Пишем в stg.hits_raw_dist, а не в локальную таблицу: раскладку по шардам -- обязан определять ключ шардирования, а не то, какая нода случайно читала -- топик. Вставка при этом фоновая — окно потери принято осознанно, довод -- целиком в docs/architecture/storage.md, раздел «Приём». -- -- Служебные колонки заполняются выражением здесь, а не DEFAULT в таблице. -- Для consumer_host это обязательно: проверено на стенде 5 августа 2026 года — -- DEFAULT hostName() вычисляется на шарде-получателе и назвал бы не ту ноду, -- которая читала топик. hostName() в SELECT снимается на вставляющей ноде, -- то есть отвечает ровно на нужный вопрос. -- -- Порядок колонок в SELECT совпадает с порядком в целевой таблице. CREATE MATERIALIZED VIEW IF NOT EXISTS stg.hits_raw_mv ON CLUSTER clickstream_cluster TO stg.hits_raw_dist AS SELECT raw, _topic AS kafka_topic, _partition AS kafka_partition, _offset AS kafka_offset, _timestamp_ms AS kafka_timestamp, hostName() AS consumer_host, now64(3) AS _load_ts FROM stg.hits_raw_kafka;