-- Pre-aggregated 5-minute stats rollup for route executions. -- Uses AggregatingMergeTree with -State/-Merge combinators so intermediate -- aggregates can be merged across arbitrary time windows and dimensions. -- Drop existing objects to allow schema changes (MV must be dropped before table) DROP VIEW IF EXISTS route_execution_stats_5m_mv; DROP TABLE IF EXISTS route_execution_stats_5m; CREATE TABLE route_execution_stats_5m ( bucket DateTime('UTC'), route_id LowCardinality(String), agent_id LowCardinality(String), total_count AggregateFunction(count), failed_count AggregateFunction(countIf, UInt8), duration_sum AggregateFunction(sum, UInt64), p99_duration AggregateFunction(quantileTDigest(0.99), UInt64) ) ENGINE = AggregatingMergeTree() PARTITION BY toYYYYMMDD(bucket) ORDER BY (agent_id, route_id, bucket) TTL bucket + toIntervalDay(30) SETTINGS ttl_only_drop_parts = 1; CREATE MATERIALIZED VIEW route_execution_stats_5m_mv TO route_execution_stats_5m AS SELECT toStartOfFiveMinutes(start_time) AS bucket, route_id, agent_id, countState() AS total_count, countIfState(status = 'FAILED') AS failed_count, sumState(duration_ms) AS duration_sum, quantileTDigestState(0.99)(duration_ms) AS p99_duration FROM route_executions GROUP BY bucket, route_id, agent_id;