-- DM: физические дневные витрины и доноры их партиций. -- Выручка хранится в зерне «день заказа × категория товара». День служит -- единицей пересборки, поэтому совпадает с ключом партиции. CREATE TABLE IF NOT EXISTS dm.revenue_daily_rep ON CLUSTER clickstream_cluster ( report_date Date, product_category LowCardinality(String), orders UInt64, units UInt64, revenue Decimal(18, 2), aov Decimal(18, 2), _load_id String, _load_ts DateTime64(3, 'UTC') ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/{database}/{table}', '{replica}') PARTITION BY report_date ORDER BY (report_date, product_category); -- Категория — единственное измерение кроме дня. Шесть категорий стартового -- мира близки по объему, поэтому простой ключ раскладывает строки достаточно -- ровно и не добавляет в учебный пример составной хеш без читателя. CREATE TABLE IF NOT EXISTS dm.revenue_daily_dist ON CLUSTER clickstream_cluster AS dm.revenue_daily_rep ENGINE = Distributed( 'clickstream_cluster', 'dm', 'revenue_daily_rep', cityHash64(product_category) ); -- Донор объявлен через AS и шардируется тем же ключом, что цель. REPLACE -- PARTITION идет по локальным таблицам, поэтому структура и раскладка донора -- обязаны совпадать с целью (docs/architecture/storage.md, «Раскладка по -- шардам»). CREATE TABLE IF NOT EXISTS dm.revenue_daily_stage_rep ON CLUSTER clickstream_cluster AS dm.revenue_daily_rep ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/{database}/{table}', '{replica}') PARTITION BY report_date ORDER BY (report_date, product_category); CREATE TABLE IF NOT EXISTS dm.revenue_daily_stage_dist ON CLUSTER clickstream_cluster AS dm.revenue_daily_stage_rep ENGINE = Distributed( 'clickstream_cluster', 'dm', 'revenue_daily_stage_rep', cityHash64(product_category) ); -- Сверка хранит одну строку на заказ. День — единица пересборки: пока рядом -- живут два источника, строка может перейти из awaiting_order в обычный класс. CREATE TABLE IF NOT EXISTS dm.purchase_vs_orders_rep ON CLUSTER clickstream_cluster ( order_day Date, order_id String, declared_revenue Nullable(Decimal(18, 2)), items_total Nullable(Decimal(18, 2)), status LowCardinality(Nullable(String)), mismatch_class LowCardinality(String), _load_id String, _load_ts DateTime64(3, 'UTC') ) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/{database}/{table}', '{replica}') PARTITION BY order_day ORDER BY (order_day, order_id); -- Ключ совпадает с DDS, поэтому строка заказа на всех слоях попадает на один -- шард. CREATE TABLE IF NOT EXISTS dm.purchase_vs_orders_dist ON CLUSTER clickstream_cluster AS dm.purchase_vs_orders_rep ENGINE = Distributed( 'clickstream_cluster', 'dm', 'purchase_vs_orders_rep', cityHash64(order_id) ); -- Донор повторяет структуру и раскладку цели по правилу, разобранному у -- revenue_daily_stage_rep и в docs/architecture/storage.md. CREATE TABLE IF NOT EXISTS dm.purchase_vs_orders_stage_rep ON CLUSTER clickstream_cluster AS dm.purchase_vs_orders_rep ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/{database}/{table}', '{replica}') PARTITION BY order_day ORDER BY (order_day, order_id); CREATE TABLE IF NOT EXISTS dm.purchase_vs_orders_stage_dist ON CLUSTER clickstream_cluster AS dm.purchase_vs_orders_stage_rep ENGINE = Distributed( 'clickstream_cluster', 'dm', 'purchase_vs_orders_stage_rep', cityHash64(order_id) ); -- Трафик пересчитывается целиком: новая связь куки с пользователем меняет -- прошлые дни. Версия запуска позволяет точному представлению скрыть строки -- прежних пересчетов без TRUNCATE и без партиций. CREATE TABLE IF NOT EXISTS dm.daily_traffic_rep ON CLUSTER clickstream_cluster ( report_date Date, visitors UInt64, known_users UInt64, _load_id String, _load_ts DateTime64(3, 'UTC') ) ENGINE = ReplicatedReplacingMergeTree( '/clickhouse/tables/{shard}/{database}/{table}', '{replica}', _load_ts ) ORDER BY report_date; -- Все версии одного дня должны попадать на один шард, иначе FINAL не сможет -- выбрать последнюю через границу шардов. CREATE TABLE IF NOT EXISTS dm.daily_traffic_dist ON CLUSTER clickstream_cluster AS dm.daily_traffic_rep ENGINE = Distributed( 'clickstream_cluster', 'dm', 'daily_traffic_rep', cityHash64(report_date) );