Materialized View Chains — Multi-Layer Aggregation Pipelines

Materialized View Chains — Multi-Layer Aggregation Pipelines

A materialized view can be built on top of another materialized view. This creates a pipeline: raw data → hourly rollup → daily rollup → weekly rollup. Each layer is cheaper to query and easier to reason about.

DROP MATERIALIZED VIEW IF EXISTS mv_weekly_tweets, mv_daily_tweets, mv_hourly_tweets CASCADE;

-- Layer 1: hourly tweet stats (refreshed every hour)
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_hourly_tweets AS
SELECT
    user_id,
    DATE_TRUNC('hour', created_at)     AS hour_bucket,
    COUNT(*)                              AS tweets,
    SUM(like_count)                       AS likes,
    SUM(impression_count)                 AS impressions
FROM tw_tweets
GROUP BY user_id, DATE_TRUNC('hour', created_at)
WITH DATA;

CREATE UNIQUE INDEX IF NOT EXISTS idx_mvht_user_hour ON mv_hourly_tweets (user_id, hour_bucket);

-- Layer 2: daily stats built FROM the hourly mat view (refreshed daily)
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_daily_tweets AS
SELECT
    user_id,
    hour_bucket::DATE                    AS day,
    SUM(tweets)                          AS tweets,
    SUM(likes)                           AS likes,
    SUM(impressions)                     AS impressions,
    ROUND(100.0 * SUM(likes)
          / NULLIF(SUM(impressions), 0), 4) AS engagement_rate
FROM mv_hourly_tweets   -- reads from Layer 1
GROUP BY user_id, hour_bucket::DATE
WITH DATA;

CREATE UNIQUE INDEX IF NOT EXISTS idx_mvdt_user_day ON mv_daily_tweets (user_id, day);

-- Layer 3: weekly summary built FROM the daily mat view (refreshed weekly)
CREATE MATERIALIZED VIEW IF NOT EXISTS mv_weekly_tweets AS
SELECT
    user_id,
    DATE_TRUNC('week', day)::DATE       AS week_start,
    SUM(tweets)                           AS tweets,
    SUM(likes)                            AS likes,
    ROUND(AVG(engagement_rate), 4)        AS avg_daily_engagement
FROM mv_daily_tweets    -- reads from Layer 2
GROUP BY user_id, DATE_TRUNC('week', day)
WITH DATA;

CREATE UNIQUE INDEX IF NOT EXISTS idx_mvwt_user_week ON mv_weekly_tweets (user_id, week_start);

Purchase this course to unlock the full lesson.

Sign up