Windows divide continuous streams into finite chunks for time-based aggregations. Instead of accumulating state forever, windowed queries aggregate data within bounded time intervals and emit results when windows close.
-- UTC (default)SELECT window_start, count() as eventsFROM tumble(logs, 1h)GROUP BY window_start;-- Eastern TimeSELECT window_start, count() as events FROM tumble(logs, 1h, 'America/New_York')GROUP BY window_start;-- Tokyo TimeSELECT window_start, count() as eventsFROM tumble(logs, 1h, 'Asia/Tokyo')GROUP BY window_start;
-- 5-minute average, updated every minuteSELECT window_start, sensor_id, avg(temperature) as avg_temp, max(temperature) as max_temp, min(temperature) as min_tempFROM hop(sensors, 1m, 5m)GROUP BY window_start, sensor_id;
Use case: Smooth out spikes while maintaining recent context.
-- Update dashboard every 10 seconds with last 1 minute of dataCREATE MATERIALIZED VIEW mv_dashboard_metrics INTO dashboard_data ASSELECT window_end as timestamp, service, count() as requests_per_min, avg(latency_ms) as avg_latency, quantile(0.95)(latency_ms) as p95_latency, count_if(status >= 500) as errorsFROM hop(access_logs, 10s, 1m)GROUP BY window_end, service;
-- Group user clicks into sessions (30-minute timeout)SELECT window_start as session_start, window_end as session_end, user_id, count() as clicks_in_session, date_diff('second', window_start, window_end) as session_duration_secFROM session(clickstream, 30m)GROUP BY window_start, window_end, user_id;
-- Get window start timetumble_start(time_column, interval [, timezone])-- Get window end time tumble_end(time_column, interval [, timezone])-- ExampleSELECT tumble_start(_tp_time, 1h) as hour, count() as eventsFROM logsGROUP BY hour;
-- Get window start timehop_start(time_column, hop_interval, window_interval [, timezone])-- Get window end timehop_end(time_column, hop_interval, window_interval [, timezone])-- Example SELECT hop_start(_tp_time, 30s, 1m) as window_start, hop_end(_tp_time, 30s, 1m) as window_end, count() as eventsFROM logsGROUP BY window_start, window_end;
-- Per-minute traffic statisticsSELECT window_start, url_path, count() as requests, count(DISTINCT ip_address) as unique_visitors, avg(response_time_ms) as avg_response_time, quantile(0.5)(response_time_ms) as median_response_time, quantile(0.95)(response_time_ms) as p95_response_time, sum(bytes_sent) as total_bytesFROM tumble(access_logs, 1m)GROUP BY window_start, url_pathORDER BY requests DESC;
-- 5-minute error rate by serviceSELECT window_start, service, count() as total_requests, count_if(status >= 500) as errors, errors / total_requests * 100 as error_rate_pctFROM tumble(logs, 5m)GROUP BY window_start, serviceHAVING error_rate_pct > 5; -- Alert if >5% errors
-- 10-minute moving average (1-minute slide)SELECT window_end as timestamp, sensor_id, avg(value) as moving_avg, stddev(value) as stddevFROM hop(sensor_readings, 1m, 10m)GROUP BY window_end, sensor_id;
-- Find 5-minute windows with abnormal loadWITH window_stats AS ( SELECT window_start, count() as events, avg(cpu_usage) as avg_cpu FROM tumble(metrics, 5m) GROUP BY window_start)SELECT *FROM window_statsWHERE events > (SELECT avg(events) * 2 FROM window_stats) -- 2x average OR avg_cpu > 80; -- Or high CPU
-- Top 10 products by sales per hourSELECT window_start, product_id, sum(quantity) as units_sold, sum(amount) as revenueFROM tumble(orders, 1h)GROUP BY window_start, product_idORDER BY window_start, revenue DESCLIMIT 10 BY window_start; -- Top 10 per window
-- Partition windows by high-cardinality keySELECT window_start, user_id, -- Millions of users count() as eventsFROM tumble(clickstream, 1h)GROUP BY window_start, user_idSETTINGS max_memory_usage='4GB', -- Limit memory per query group_by_overflow_mode='any'; -- Graceful degradation
-- Control when window results emitSELECT window_start, count() as eventsFROM tumble(logs, 1m)GROUP BY window_startEMIT AFTER WATERMARK, -- Emit when window closes ON UPDATE; -- Or on every update (default)
-- Wrong: Missing window in GROUP BYSELECT count() FROM tumble(events, 1m);-- Error: window_start and window_end not in GROUP BY-- CorrectSELECT window_start, count()FROM tumble(events, 1m)GROUP BY window_start;
Mixing window types
-- Wrong: Can't mix tumble and hopSELECT tumble_start(_tp_time, 1m), hop_start(_tp_time, 30s, 1m), -- Different window types! count()FROM events;-- Correct: Use one window typeSELECT window_start, window_end, count()FROM tumble(events, 1m)GROUP BY window_start, window_end;