
Você ainda evita CTEs no Postgres por medo da materialização? Se a sua base de conhecimento parou no PostgreSQL 11, você está deixando a performance na mesa.
Otimizar consultas modernas exige entender onde termina a organização de código e onde começa a barreira de otimização. Antigamente, a escolha entre uma subquery e uma CTE era simples: uma era rápida, a outra era legível. Hoje, essa linha se tornou tênue. Para o especialista, a pergunta não é mais “qual é o mais bonito”, mas sim: “como o Planner vai reescrever o meu SQL por baixo do capô?”.
Neste artigo, vamos colocar Subqueries, CTEs e Views frente a frente, analisando como o motor do Postgres evoluiu para tratar essas estruturas e qual delas realmente escala quando o volume de dados deixa de ser trivial.
A Queda do Muro: CTEs (WITH queries)
Durante anos, o Postgres tratava toda CTE como uma “Optimization Barrier”. O banco executava a query interna, salvava o resultado em disco/memória (materialização) e só então seguia adiante.
- A Evolução: Desde a versão 12, o Postgres se tornou inteligente. Se sua CTE for simples, o otimizador pode decidir fazer o inline dela, fundindo-a com a query principal como se fosse uma subquery.
- O Veredito do Especialista: Use CTEs para organizar fluxos lógicos complexos sem medo, mas monitore o EXPLAIN. Se precisar forçar o comportamento antigo por questões de performance específica, o comando WITH cte_name AS MATERIALIZED (…) é sua ferramenta de precisão.
Subqueries: O “Inline” Nativo
Subqueries são o terreno seguro para o otimizador. Como elas não têm a promessa de isolamento das CTEs, o Postgres tem liberdade total para “achatar” a consulta, reordenar JOINS e aplicar filtros no nível mais baixo possível.
- O Comportamento: Elas são quase sempre transformadas em sub-joins.
- O Risco: O custo aqui é humano. Consultas aninhadas em excesso tornam a manutenção um pesadelo e escondem erros de lógica que uma CTE deixaria óbvios.
Views: A Abstração que Pode Cobrar Juros
Views não são tabelas físicas; elas funcionam como atalhos lógicos para consultas. Quando você consulta uma View, o Postgres expande aquela definição dentro da sua query antes de otimizar.
- O Perigo do “Nesting”: O problema surge quando uma View chama outra View, que por sua vez faz um JOIN com uma terceira. O plano de execução pode explodir em complexidade, tornando impossível para o otimizador escolher o melhor índice.
- A Boa Prática: Views são para interface e segurança. Se a performance degradar, talvez seja hora de considerar uma Materialized View (com uma estratégia de refresh sólida) ou transformar a lógica em uma função.
O Raio-X da Decisão
| Abordagem | Impacto no Planner | Legibilidade | Melhor Uso |
| Subquery | Mínimo (Transparente) | Baixa | Filtros rápidos e pontuais. |
| CTE | Configurável (v12+) | Altíssima | Lógica sequencial e relatórios. |
| View | Expansivo | Alta | Padronização de regras de negócio. |
O EXPLAIN ANALYZE é seu único juiz
A evolução do PostgreSQL eliminou o antigo “imposto de performance” que muitas vezes penalizava um SQL mais organizado e legível. Hoje é possível escrever código limpo sem abrir mão de eficiência.
Ainda assim, decisões técnicas devem ser baseadas em evidências — não em suposições. Não presuma que uma estrutura é melhor do que outra. Execute, meça e obrigue o banco a revelar o plano de execução.
No fim, é o EXPLAIN ANALYZE que determina o que realmente é mais eficiente.
Se você enxerga um CTE Scan no seu plano de execução onde esperava um Index Scan, você acabou de encontrar onde sua query está perdendo a guerra contra o tempo.
Quer receber mais conteúdos como esse?
Assine nossa newsletter. Menos “Hello World”, mais engenharia de verdade direto na sua caixa de entrada.