REFRESH MATERIALIZED VIEW — Full vs CONCURRENTLY

REFRESH MATERIALIZED VIEW — Full vs CONCURRENTLY

Refreshing a materialized view replaces its content with a fresh query result. Two modes: full (blocks all reads during refresh) and CONCURRENTLY (non-blocking but requires a unique index and runs slower).

-- Full refresh: locks the view for the duration (readers blocked)
REFRESH MATERIALIZED VIEW mv_user_stats;

-- CONCURRENTLY: builds new data alongside old, swaps atomically — no read lock
-- Requires a unique index on the mat view
REFRESH MATERIALIZED VIEW CONCURRENTLY mv_user_stats;

-- Check when a mat view was last refreshed
-- (store computed_at inside the view itself)
SELECT MAX(computed_at) AS last_refresh FROM mv_user_stats;

How CONCURRENTLY works internally

1. Compute new result set into a temp staging area
2. Diff old vs new: find inserted, updated, deleted rows
3. Apply diff to the mat view in a single transaction
4. Readers see the old version until the swap completes
-- Practical refresh schedule: wrap in a function for error handling
CREATE OR REPLACE FUNCTION refresh_user_stats()
RETURNS void LANGUAGE plpgsql AS $$
BEGIN
    REFRESH MATERIALIZED VIEW CONCURRENTLY mv_user_stats;
    RAISE NOTICE 'mv_user_stats refreshed at %', NOW();
EXCEPTION WHEN OTHERS THEN
    RAISE WARNING 'Refresh failed: %', SQLERRM;
END;
$$;

SELECT refresh_user_stats();

Purchase this course to unlock the full lesson.

Sign up