CREATE MATERIALIZED VIEW și REFRESH în PostgreSQL

Tabele, scheme și tipuri (DDL) PostgreSQL 9.3+ (REFRESH CONCURRENTLY: 9.4+)

View care salvează rezultatul interogării pe disc. Citirea este rapidă, iar datele se actualizează doar când rulezi REFRESH.

Sintaxă SQL
CREATE MATERIALIZED VIEW [IF NOT EXISTS] nume AS
    interogare
    [WITH [NO] DATA];

REFRESH MATERIALIZED VIEW [CONCURRENTLY] nume [WITH [NO] DATA];

Ce face CREATE MATERIALIZED VIEW și REFRESH

Un view materializat rulează interogarea o dată și păstrează rezultatul ca pe un tabel. Este potrivit pentru rapoarte grele (agregări pe milioane de rânduri) care nu trebuie să fie actuale la secundă.

Datele nu se actualizează singure. REFRESH MATERIALIZED VIEW rulează din nou interogarea și înlocuiește conținutul. Varianta simplă blochează citirile pe durata refresh-ului. Cu CONCURRENTLY, citirile continuă, dar view-ul trebuie să aibă un index UNIQUE fără WHERE.

Pe un view materializat poți crea indecși, ca pe un tabel. Refresh-ul periodic se programează de obicei cu cron sau cu extensia pg_cron.

Parametri

Parametru Descriere
WITH NO DATA Creează view-ul gol; nu poate fi citit până la primul REFRESH.
CONCURRENTLY Refresh fără să blocheze citirile. Cere un index unic și durează mai mult.

Ce returnează

SELECT n la creare (n = rândurile salvate) și REFRESH MATERIALIZED VIEW la refresh.

Exemple

Exemplul 1: Vânzări pe lună, precalculate

CREATE MATERIALIZED VIEW vanzari_lunare AS
SELECT date_trunc('month', creat_la)::date AS luna,
       count(*) AS comenzi,
       sum(total) AS incasari
FROM comenzi
GROUP BY 1;

SELECT * FROM vanzari_lunare ORDER BY luna;

Rezultat în psql

SELECT 3
    luna    | comenzi | incasari 
------------+---------+----------
 2026-08-01 |     312 | 48210.40
 2026-09-01 |     355 | 53987.10
 2026-10-01 |     298 | 45102.85
(3 rows)

Exemplul 2: Refresh fără blocarea citirilor

REFRESH MATERIALIZED VIEW CONCURRENTLY vanzari_lunare;

CREATE UNIQUE INDEX ON vanzari_lunare (luna);
REFRESH MATERIALIZED VIEW CONCURRENTLY vanzari_lunare;

Rezultat în psql

ERROR:  cannot refresh materialized view "public.vanzari_lunare" concurrently
HINT:  Create a unique index with no WHERE clause on one or more columns of the materialized view.
CREATE INDEX
REFRESH MATERIALIZED VIEW

Exemplul 3: View creat gol

CREATE MATERIALIZED VIEW top_produse AS
SELECT produs, sum(cantitate) AS bucati FROM linii_comanda GROUP BY produs
WITH NO DATA;

SELECT * FROM top_produse;

Rezultat în psql

CREATE MATERIALIZED VIEW
ERROR:  materialized view "top_produse" has not been populated
HINT:  Use the REFRESH MATERIALIZED VIEW command.

Greșeli frecvente

  • Uiți că datele nu se actualizează singure și afișezi pe site cifre vechi de o săptămână. Programează refresh-ul.
  • Folosești CONCURRENTLY fără index unic și primești eroare. Creează mai întâi indexul.

Comenzi înrudite

  • CREATE VIEW: Salvează o interogare sub un nume, ca s-o folosești ca pe un tabel. Datele nu se copiază: interogarea rulează la fiecare citire.
  • CREATE TABLE AS și LIKE: Creează un tabel din rezultatul unei interogări (CREATE TABLE AS) sau copiind structura altui tabel (LIKE).