sqlpostgresqlmaterialized-viewperformance

Visoes materializadas no SQL: cache de consultas caras

Como uma visao materializada faz cache do resultado de uma consulta pesada, como o REFRESH funciona e quando uma view comum ou tabela resumo encaixa melhor.

2 min de leituraReferencesql · postgresql · materialized-view · performance · caching

Uma visao materializada e uma consulta cujo resultado fica armazenado fisicamente em disco como uma tabela. Voce paga o SELECT pesado uma unica vez, no refresh, e depois le a resposta pre-calculada em milissegundos.

Por que usar

Uma VIEW comum e apenas o texto da consulta guardado: cada acesso reexecuta o plano. Se ela agrega milhoes de linhas ou junta meia tabela, seu dashboard rasteja. A visao materializada calcula o resultado de antemao e o mantem guardado.

CREATE MATERIALIZED VIEW revenue_by_country AS
SELECT u.country,
       count(*)        AS orders_cnt,
       sum(o.amount)   AS revenue
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE o.status = 'paid'
GROUP BY u.country;

Agora SELECT * FROM revenue_by_country le linhas ja calculadas sem tocar em orders e users. O detalhe: os dados ficam congelados no momento do ultimo refresh.

Atualizando: REFRESH e CONCURRENTLY

Para puxar dados novos, voce recalcula a visao:

REFRESH MATERIALIZED VIEW revenue_by_country;

O problema: um REFRESH comum pega um lock ACCESS EXCLUSIVE, entao os leitores ficam travados enquanto ele roda. Em volumes grandes sao segundos de indisponibilidade. A solucao e CONCURRENTLY: os novos dados sao construidos em segundo plano e trocados de forma atomica sem bloquear o SELECT.

-- CONCURRENTLY exige um indice UNIQUE sobre as linhas do resultado
CREATE UNIQUE INDEX ON revenue_by_country (country);

REFRESH MATERIALIZED VIEW CONCURRENTLY revenue_by_country;
  • Sem indice unico, CONCURRENTLY retorna erro.
  • CONCURRENTLY e mais lento (compara linha por linha) mas nunca bloqueia as leituras.
  • Dispare o refresh por agendamento (cron, pg_cron) ou como passo apos o ETL.

Indexando a visao

Uma visao materializada e uma tabela, entao voce pode colocar indices normais nela e acelerar as leituras sobre ela.

CREATE INDEX idx_rev_revenue ON revenue_by_country (revenue DESC);

SELECT country, revenue
FROM revenue_by_country
ORDER BY revenue DESC
LIMIT 10;

Os indices sobrevivem a um REFRESH: o Postgres os reconstroi por voce. So lembre: quanto mais indices voce adiciona, mais lento fica cada refresh.

Dados defasados: o compromisso central

O preco da velocidade sao dados defasados. Entre dois REFRESH, a visao mostra uma foto antiga.

Gotcha: um usuario faz um pedido, mas ele nao aparece em revenue_by_country ate voce chamar REFRESH. Nunca use uma visao materializada onde precise de exatidao transacional (saldos de conta, estoque).

Ajuste a cadencia ao negocio: um dashboard analitico fica bem atualizando de hora em hora; quase tempo real precisa de cada par de minutos.

View, MV ou tabela resumo

Opcao Dados Quando usar
VIEW sempre frescos consulta leve, exige atualidade
MATERIALIZED VIEW do ultimo refresh consulta pesada, tolera atraso
tabela resumo voce mantem precisa de logica incremental e UPSERT

Uma tabela resumo e o equivalente manual: voce a preenche com INSERT ... SELECT e a atualiza de forma incremental por conta propria.

INSERT INTO revenue_summary (country, revenue, day)
SELECT u.country, sum(o.amount), current_date
FROM orders o
JOIN users u ON u.id = o.user_id
WHERE o.created_at >= current_date
GROUP BY u.country
ON CONFLICT (country, day) DO UPDATE
SET revenue = EXCLUDED.revenue;

Diferencas por banco:

  • MySQL nao tem visoes materializadas: voce as emula com tabelas resumo mais triggers ou o agendador de eventos.
  • ClickHouse tem MATERIALIZED VIEW, mas nao e um cache: e um gatilho incremental que atualiza agregados a cada insercao na tabela de origem.

A regra e simples: precisa de atualidade, use uma VIEW; a consulta e cara e o atraso e aceitavel, use uma MATERIALIZED VIEW; precisa de logica incremental fina, monte sua propria tabela resumo.

Pratique com exercícios reais

Resolva exercícios no treinador de SQL com correção instantânea e dicas.

Abrir o treinador