Normalização vs. Desnormalização
Normalização e desnormalização são geralmente apresentadas como opostas, mas elas respondem à mesma questão subjacente a partir de direções diferentes: quanta redundância este esquema deve tolerar.
Busque em todas as páginas da documentação
Normalização e desnormalização são geralmente apresentadas como opostas, mas elas respondem à mesma questão subjacente a partir de direções diferentes: quanta redundância este esquema deve tolerar.
A normalização remove a redundância para proteger a correção; a desnormalização reintroduz parte dela, de propósito, para tornar leituras específicas mais rápidas.
Esta página explica o raciocínio por trás de ambas, para que o restante das páginas desta seção sobre formas normais, views materializadas e desnormalização intencional sejam lidas como ferramentas em um espectro, em vez de campos concorrentes.
JOIN desnecessário (super-normalizada) em escala de produção.JOINs em tempo de leitura; a desnormalização custa trabalho de consistência em tempo de escrita.Normalização é o processo de organizar colunas e tabelas de forma que cada fato seja armazenado em exatamente um lugar.
É impulsionada por dependências funcionais: se um valor como nome_produto é totalmente determinado por sku, então nome_produto pertence à tabela com chave sku, não copiado em cada linha que referencia esse produto.
As formas normais formais (1NF, 2NF, 3NF e adiante) são pontos de verificação nomeados ao longo deste processo, cada uma fechando uma categoria específica de redundância.
O benefício da normalização é que uma anomalia de atualização se torna estruturalmente impossível: um fato armazenado em um lugar não pode entrar em conflito consigo mesmo.
Desnormalização viola deliberadamente esse princípio armazenando um valor derivado ou duplicado em um lugar onde não era estritamente necessário, em troca de evitar um JOIN em tempo de leitura.
As duas técnicas não são estágios de maturidade, onde a normalização é "correta" e a desnormalização é uma alternativa; elas são um trade-off genuíno entre garantias de correção em tempo de escrita e custo em tempo de leitura.
-- Normalizado: order_items não tem dados de produto duplicados
SELECT oi.order_id, p.name, p.sku
FROM order_items oi
JOIN products p ON p.product_id = oi.product_id;A maioria dos esquemas de produção não é puramente um ou outro; eles normalizam o núcleo do domínio com muitas escritas e desnormalizam um pequeno número de caminhos de leitura específicos e conhecidos como "quentes".
A decisão de onde se situar neste espectro deve seguir a razão leitura/escrita real de uma tabela, não uma preferência geral.
Uma tabela escrita uma vez e lida milhares de vezes por escrita é um forte candidato para alguma desnormalização, porque o custo de manter um valor duplicado em sincronia é pago raramente em relação a quantas vezes o atalho compensa.
Uma tabela escrita e lida em taxas semelhantes ganha pouco com a desnormalização, porque o custo de sincronização e o benefício de evitar JOINs se cancelam aproximadamente.
O PostgreSQL oferece uma view materializada como uma forma estruturada de desnormalizar sem abandonar as tabelas normalizadas como fonte de verdade.
CREATE MATERIALIZED VIEW order_totals AS
SELECT order_id, SUM(amount) AS total
FROM order_items
GROUP BY order_id;
-- Atualizada explicitamente, não em cada escrita subjacente
REFRESH MATERIALIZED VIEW order_totals;A view materializada contém uma forma desnormalizada e pré-computada, mas as tabelas normalizadas subjacentes permanecem a fonte de verdade a partir da qual a view é atualizada.
Essa etapa de atualização é o cerne de toda decisão de desnormalização: alguém tem que decidir quão desatualizada a cópia desnormalizada pode ser, e qual mecanismo (um trigger, um job agendado, uma escrita em nível de aplicação) a mantém dentro desse limite.
Uma coluna desnormalizada sem um caminho de atualização definido não é uma otimização de performance, é um bug de correção que se acumula lentamente.
Em escala, o argumento da razão leitura/escrita se estende à distinção OLTP versus OLAP que molda o design de um sistema inteiro, não apenas uma tabela.
Cargas de trabalho OLTP (muitas transações pequenas, fortes necessidades de consistência) tendem à normalização, porque a correção sob escritas concorrentes é mais importante do que economizar um JOIN em um relatório raro.
Cargas de trabalho OLAP (grandes consultas agregadas sobre dados históricos) tendem à desnormalização, frequentemente em tabelas de fatos e dimensões no estilo de esquema estrela, porque os dados são escritos uma vez por um processo em lote e lidos repetidamente por analistas.
A desnormalização intencional em um sistema OLTP, feita corretamente, é restrita e documentada: uma coluna específica, uma consulta "quente" específica, um mecanismo de consistência específico declarado, em vez de uma política geral de duplicação de dados onde quer que pareça conveniente.
| Abordagem | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
| Normalização completa (3NF+) | Sem anomalias de atualização; fonte única de verdade por fato | Caminhos de leitura podem exigir vários JOINs | Tabelas OLTP com escritas frequentes e concorrentes |
| View materializada | Velocidade de leitura desnormalizada com uma fonte de verdade normalizada intacta | Dados podem estar desatualizados entre atualizações | Agregados caros lidos com muito mais frequência do que a origem muda |
| Coluna desnormalizada ad hoc | Leitura mais rápida possível para essa única coluna | Requer um mecanismo de sincronização explícito; fácil de esquecer | Um único caminho "quente" comprovado com um proprietário claro |
| Esquema estrela (fato/dimensão) | Otimizado para grandes varreduras agregadas | Mau ajuste para escritas transacionais de alta concorrência | Cargas de trabalho OLAP e de relatórios |
O modo de falha honesto neste espectro não é escolher a desnormalização, é escolhê-la silenciosamente, sem anotar a tolerância à desatualização ou o mecanismo de atualização em qualquer lugar que um futuro engenheiro possa encontrar.
REFRESH, e o PostgreSQL não a atualiza automaticamente a menos que algo seja agendado ou acionado para fazê-lo.JOIN bem indexado em um esquema normalizado é frequentemente rápido o suficiente, e a desnormalização prematura adiciona risco de sincronização para um problema de performance que pode ainda não existir.A normalização armazena cada fato em exatamente um lugar para prevenir contradições entre cópias duplicadas.
A desnormalização duplica ou pré-computa dados deliberadamente para evitar o custo de JOIN de remontá-los em tempo de leitura.
Sim, essa é a ordem padrão mais segura: normalize para estabelecer uma fonte de verdade correta, então desnormalize caminhos específicos e comprovadamente "quentes" assim que você tiver evidências de que eles precisam disso.
Desnormalizar especulativamente, antes que um padrão de leitura real exista, adiciona risco sem um benefício correspondente.
Uma dependência funcional A -> B significa que o valor de A determina completamente o valor de B.
A normalização usa dependências funcionais para decidir em qual tabela um atributo pertence - se sku determina nome_produto, esse nome pertence ao SKU, não duplicado em cada linha que o referencia.
Uma view materializada armazena um resultado desnormalizado e pré-computado, enquanto as tabelas normalizadas subjacentes permanecem a fonte de verdade real.
Ela oferece velocidade em tempo de leitura sem descartar a correção em tempo de escrita, ao custo da view estar desatualizada até ser atualizada.
Tão desatualizada quanto o tempo entre as chamadas de REFRESH MATERIALIZED VIEW, já que o PostgreSQL não a atualiza automaticamente em escritas subjacentes.
A janela de desatualização aceitável é uma decisão que a equipe tem que tomar explicitamente, não uma propriedade que o PostgreSQL impõe para você.
Nesta seção, sim - a razão para desnormalizar é quase sempre para evitar o custo de JOIN em um caminho específico e frequentemente lido.
Outras razões às vezes citadas, como conveniência, geralmente são um sinal de que a desnormalização não foi deliberada o suficiente.
Olhe para sua razão de leitura/escrita real: uma tabela lida muito mais vezes do que é escrita é um candidato razoável para alguma desnormalização.
Uma tabela lida e escrita em taxas semelhantes geralmente ganha pouco com isso.
Fazer isso sem um mecanismo definido para manter o valor duplicado em sincronia com sua origem.
Uma coluna desnormalizada dessincronizada deriva silenciosamente para dados incorretos ao longo do tempo.
Não - sistemas OLTP geralmente tendem à normalização porque a correção de escrita concorrente é mais importante, enquanto sistemas OLAP tendem à desnormalização, frequentemente em esquemas estrela, porque os dados são escritos em lotes e lidos repetidamente para análise.
3NF remove as categorias de anomalias que importam para a maioria dos esquemas de aplicação, e BCNF fecha um caso de borda mais estreito envolvendo chaves candidatas sobrepostas.
A maioria das equipes tem como alvo 3NF por padrão e recorre a BCNF apenas quando esse caso de borda específico está presente.
Sim, e na prática quase sempre o fazem - a maioria dos esquemas de produção normaliza suas tabelas centrais com muitas escritas, enquanto desnormaliza um pequeno número de caminhos de leitura conhecidos e medidos.
Tratar a escolha como abrangendo todo o esquema em vez de por tabela é geralmente um erro.
Confirme se a razão leitura/escrita realmente a justifica e anote o mecanismo de atualização ou consistência antes de enviar a alteração.
Uma desnormalização sem um plano de desatualização declarado é um bug esperando para surgir, não uma otimização finalizada.
Versões da Stack: Esta página foi escrita para PostgreSQL 18.4 (estável 18, manutenção 17).
Revisado por Chris St. John·Última atualização: 15 de jul. de 2026