Introdução
Imagine uma planilha onde cada linha de um pedido guarda também o nome do cliente, o email, a cidade, o nome do produto e a categoria — tudo junto. Funciona no começo. Mas conforme o sistema cresce, começam a aparecer problemas silenciosos: dados duplicados, inconsistências difíceis de rastrear, operações que quebram coisas inesperadas. A normalização existe para eliminar esses problemas sistematicamente.
Proposta por Codd nos anos 1970 e formalizada ao longo das décadas seguintes, a normalização é um processo de reorganização do esquema em formas normais progressivas — cada uma corrigindo uma classe específica de problema.
O problema: Anomalias
Antes de ver as soluções, vale entender o que está sendo resolvido. Um esquema mal estruturado produz três tipos de anomalia.
Considere esta tabela que mistura informações de pedidos, clientes e produtos:
| pedido_id | cliente | cliente_cidade | produto | categoria | qtd | preco |
|-----------|------------|----------------|-------------|--------------|-----|---------|
| 1 | Ana Lima | São Paulo | Notebook | Eletrônicos | 1 | 3500.00 |
| 1 | Ana Lima | São Paulo | Mouse | Periféricos | 2 | 80.00 |
| 2 | Bruno Melo | Curitiba | Notebook | Eletrônicos | 1 | 3500.00 |
Anomalia de atualização: se Ana Lima mudar de cidade, é preciso atualizar todas as linhas onde ela aparece. Esquecer uma cria inconsistência — o mesmo cliente com duas cidades diferentes no banco.
Anomalia de inserção: não é possível cadastrar um produto sem vinculá-lo a um pedido. O produto não existe de forma independente nesse esquema.
Anomalia de exclusão: se o pedido 2 for deletado, os dados do Notebook somem junto — mesmo que o produto exista em outros contextos.
Esses são os sintomas de um esquema não normalizado. As formas normais são o tratamento.
Primeira Forma Normal — 1FN
Regra: cada coluna deve conter um valor atômico — indivisível. Não pode haver listas, conjuntos ou grupos repetidos dentro de uma célula.
Um exemplo que viola 1FN:
| pedido_id | cliente | produtos |
|-----------|----------|-----------------------------|
| 1 | Ana Lima | Notebook, Mouse, Teclado |
A coluna produtos guarda múltiplos valores numa célula só. Isso parece conveniente, mas impossibilita filtrar pedidos que contenham um produto específico sem recorrer a gambiarras com LIKE.
A correção é expandir cada valor em sua própria linha:
| pedido_id | cliente | produto |
|-----------|----------|----------|
| 1 | Ana Lima | Notebook |
| 1 | Ana Lima | Mouse |
| 1 | Ana Lima | Teclado |
Além de valores atômicos, 1FN exige que cada linha seja única — o que leva naturalmente à definição de uma chave primária.
Segunda Forma Normal — 2FN
Regra: estar em 1FN e não ter dependências parciais — todo atributo não-chave deve depender da chave primária inteira, não de apenas parte dela.
Essa forma só é relevante quando a chave primária é composta. Considere:
| pedido_id | produto_id | produto_nome | cliente | quantidade |
|-----------|------------|--------------|------------|------------|
| 1 | 10 | Notebook | Ana Lima | 1 |
| 1 | 11 | Mouse | Ana Lima | 2 |
| 2 | 10 | Notebook | Bruno Melo | 1 |
A chave primária é (pedido_id, produto_id). Mas produto_nome depende apenas de produto_id — não precisa do pedido_id para ser determinado. E cliente depende apenas de pedido_id. Essas são dependências parciais.
A solução é separar em tabelas distintas, onde cada atributo depende da chave inteira da sua tabela:
-- Cada tabela tem sua própria identidade
CREATE TABLE produtos (
idINT PRIMARY KEY,
nomeVARCHAR(100)
);
CREATE TABLE pedidos (
idINT PRIMARY KEY,
cliente_idINT REFERENCES clientes(id)
);
CREATE TABLE itens_pedido (
pedido_idINT REFERENCES pedidos(id),
produto_idINT REFERENCES produtos(id),
quantidadeINT,
PRIMARY KEY (pedido_id, produto_id)
);
Agora produto_nome vive em produtos, cliente vive em pedidos, e itens_pedido guarda apenas o que é realmente da relação entre pedido e produto.
Terceira Forma Normal — 3FN
Regra: estar em 2FN e não ter dependências transitivas — nenhum atributo não-chave pode depender de outro atributo não-chave.
Exemplo:
| produto_id | nome | categoria_id | categoria_nome |
|------------|----------|--------------|----------------|
| 10 | Notebook | 1 | Eletrônicos |
| 11 | Mouse | 2 | Periféricos |
Aqui, categoria_nome não depende de produto_id diretamente — depende de categoria_id, que por sua vez depende de produto_id. Isso é uma dependência transitiva: produto_id → categoria_id → categoria_nome.
O problema: se o nome da categoria "Eletrônicos" precisar mudar, será necessário atualizar todos os produtos dessa categoria. E se não houver nenhum produto numa categoria, ela não pode ser armazenada.
A solução, novamente, é separar:
CREATE TABLE categorias (
idINT PRIMARY KEY,
nomeVARCHAR(100)
);
CREATE TABLE produtos (
idINT PRIMARY KEY,
nomeVARCHAR(100),
categoria_idINT REFERENCES categorias(id)
);
Agora categoria_nome vive onde pertence, e os produtos referenciam a categoria por chave estrangeira.
Forma Normal de Boyce-Codd — BCNF
A BCNF é uma versão mais rigorosa da 3FN, proposta em 1974 por Raymond Boyce e o próprio Codd. A diferença é sutil mas importante: na 3FN, há exceções para dependências envolvendo chaves candidatas. A BCNF elimina essas exceções.
Regra: para cada dependência funcional X → Y, X deve ser uma chave candidata.
Na prática, a maioria dos esquemas bem projetados que atingem 3FN já satisfaz a BCNF. Os casos que violam BCNF mas não 3FN são relativamente raros — envolvem tabelas com múltiplas chaves candidatas sobrepostas.
4FN e 5FN
Existem formas normais além da BCNF, que tratam de casos ainda mais específicos. A 4FN lida com dependências multivaloradas — quando um atributo determina múltiplos valores independentes de outro atributo. A 5FN trata de dependências de junção. Na prática do desenvolvimento cotidiano, chegar à 3FN ou BCNF já resolve a grande maioria dos problemas. A 4FN e 5FN aparecem em modelagens muito específicas ou acadêmicas.
Desnormalização
Normalizar é bom, mas normalizar demais pode ser um problema de desempenho. Uma consulta que precisa juntar seis tabelas para montar um relatório vai ser mais lenta do que uma que lê uma tabela única já consolidada.
Desnormalização é a decisão deliberada de violar uma forma normal em prol de desempenho. É comum em sistemas de analytics e data warehouses, onde leituras são muito mais frequentes que escritas, e a redundância de dados é um custo aceitável em troca de consultas mais rápidas.
A diferença entre um banco mal projetado e um banco desnormalizado intencionalmente é exatamente essa: consciência. Desnormalizar sem entender as formas normais é acidente. Desnormalizar conhecendo os trade-offs é arquitetura.
Top comments (0)