Normalização: 1NF, 2NF e 3NF

1. Introdução à Normalização

A normalização é um processo fundamental no design de bancos de dados relacionais que visa organizar os dados de forma eficiente, reduzindo redundâncias e evitando anomalias de inserção, atualização e exclusão. Proposta por Edgar F. Codd em 1970, a normalização estabelece um conjunto de regras chamadas "formas normais" que garantem a integridade e consistência dos dados.

As três primeiras formas normais (1NF, 2NF e 3NF) são as mais utilizadas na prática e formam a base para a maioria dos projetos de banco de dados bem estruturados. Cada forma normal resolve um tipo específico de problema estrutural, partindo da eliminação de grupos repetitivos até a remoção de dependências transitivas.

2. Primeira Forma Normal (1NF)

Definição: Uma tabela está na Primeira Forma Normal quando todos os seus atributos contêm valores atômicos (indivisíveis) e não existem grupos repetitivos de colunas.

Exemplo prático: Considere uma tabela de pedidos onde um cliente pode ter múltiplos produtos em um único pedido:

-- Tabela não normalizada (viola 1NF)
CREATE TABLE pedidos (
    pedido_id INT PRIMARY KEY,
    cliente_nome VARCHAR(100),
    cliente_telefone VARCHAR(20),
    produtos VARCHAR(200),  -- Múltiplos valores separados por vírgula
    quantidades VARCHAR(50) -- "3,2,1" - valores não atômicos
);

Problemas:
- A coluna produtos contém múltiplos valores (viola atomicidade)
- Dificuldade em consultar produtos individuais
- Anomalias de atualização (modificar um produto exige parsing da string)

Solução para 1NF: Criar uma linha para cada produto individual:

-- Tabela em 1NF
CREATE TABLE pedidos_1nf (
    pedido_id INT,
    cliente_nome VARCHAR(100),
    cliente_telefone VARCHAR(20),
    produto VARCHAR(100),
    quantidade INT,
    PRIMARY KEY (pedido_id, produto)
);
-- Inserção de dados normalizados
INSERT INTO pedidos_1nf VALUES
(1, 'João Silva', '11999999999', 'Notebook', 1),
(1, 'João Silva', '11999999999', 'Mouse', 2),
(2, 'Maria Souza', '11888888888', 'Teclado', 1);

3. Segunda Forma Normal (2NF)

Pré-requisito: A tabela deve estar em 1NF.

Definição: Uma tabela está na Segunda Forma Normal quando está em 1NF e todos os atributos não chave dependem completamente da chave primária completa (eliminação de dependências funcionais parciais).

Exemplo: A tabela pedidos_1nf ainda possui dependências parciais. O cliente_nome e cliente_telefone dependem apenas do pedido_id, não do produto.

-- Tabela em 1NF com dependências parciais
-- cliente_nome depende apenas de pedido_id, não de (pedido_id, produto)
SELECT * FROM pedidos_1nf;

Processo de decomposição para 2NF:

-- Tabela de pedidos (2NF)
CREATE TABLE pedidos_2nf (
    pedido_id INT PRIMARY KEY,
    cliente_nome VARCHAR(100),
    cliente_telefone VARCHAR(20)
);

-- Tabela de itens do pedido (2NF)
CREATE TABLE itens_pedido_2nf (
    pedido_id INT,
    produto VARCHAR(100),
    quantidade INT,
    PRIMARY KEY (pedido_id, produto),
    FOREIGN KEY (pedido_id) REFERENCES pedidos_2nf(pedido_id)
);
-- Inserção nos dados normalizados
INSERT INTO pedidos_2nf VALUES
(1, 'João Silva', '11999999999'),
(2, 'Maria Souza', '11888888888');

INSERT INTO itens_pedido_2nf VALUES
(1, 'Notebook', 1),
(1, 'Mouse', 2),
(2, 'Teclado', 1);

4. Terceira Forma Normal (3NF)

Pré-requisito: A tabela deve estar em 2NF.

Definição: Uma tabela está na Terceira Forma Normal quando está em 2NF e não possui dependências funcionais transitivas (atributos não chave dependendo de outros atributos não chave).

Exemplo: Na tabela pedidos_2nf, suponha que adicionemos informações de endereço:

-- Tabela em 2NF com dependência transitiva
CREATE TABLE pedidos_2nf_transitivo (
    pedido_id INT PRIMARY KEY,
    cliente_nome VARCHAR(100),
    cliente_telefone VARCHAR(20),
    cidade VARCHAR(50),
    estado VARCHAR(20)  -- estado depende da cidade, não do pedido_id
);

Aqui, estado depende de cidade, que por sua vez depende de pedido_id. Isso cria uma dependência transitiva.

Solução para 3NF: Separar em tabelas de cliente e endereço:

-- Tabela de clientes (3NF)
CREATE TABLE clientes_3nf (
    cliente_id INT PRIMARY KEY,
    nome VARCHAR(100),
    telefone VARCHAR(20),
    cidade VARCHAR(50),
    estado VARCHAR(20)
);

-- Tabela de pedidos (3NF)
CREATE TABLE pedidos_3nf (
    pedido_id INT PRIMARY KEY,
    cliente_id INT,
    data_pedido DATE,
    FOREIGN KEY (cliente_id) REFERENCES clientes_3nf(cliente_id)
);

-- Tabela de itens do pedido (3NF)
CREATE TABLE itens_pedido_3nf (
    pedido_id INT,
    produto VARCHAR(100),
    quantidade INT,
    PRIMARY KEY (pedido_id, produto),
    FOREIGN KEY (pedido_id) REFERENCES pedidos_3nf(pedido_id)
);
-- Inserção nos dados em 3NF
INSERT INTO clientes_3nf VALUES
(1, 'João Silva', '11999999999', 'São Paulo', 'SP'),
(2, 'Maria Souza', '11888888888', 'Rio de Janeiro', 'RJ');

INSERT INTO pedidos_3nf VALUES
(1, 1, '2024-01-15'),
(2, 2, '2024-01-16');

INSERT INTO itens_pedido_3nf VALUES
(1, 'Notebook', 1),
(1, 'Mouse', 2),
(2, 'Teclado', 1);

5. Exemplo Completo Passo a Passo

Cenário inicial: Tabela de pedidos com dados misturados

-- Esquema original (não normalizado)
CREATE TABLE pedidos_original (
    pedido_id INT PRIMARY KEY,
    cliente_nome VARCHAR(100),
    cliente_telefone VARCHAR(20),
    cliente_cidade VARCHAR(50),
    cliente_estado VARCHAR(20),
    produtos VARCHAR(200),
    quantidades VARCHAR(50),
    vendedor_nome VARCHAR(100),
    vendedor_regiao VARCHAR(50)
);

Aplicação sequencial das formas normais:

  1. 1NF: Separar produtos em linhas individuais
  2. 2NF: Criar tabelas separadas para pedidos e itens
  3. 3NF: Separar dados de cliente e vendedor
-- Esquema normalizado final (3NF)
CREATE TABLE clientes (
    cliente_id INT PRIMARY KEY,
    nome VARCHAR(100),
    telefone VARCHAR(20),
    cidade VARCHAR(50),
    estado VARCHAR(20)
);

CREATE TABLE vendedores (
    vendedor_id INT PRIMARY KEY,
    nome VARCHAR(100),
    regiao VARCHAR(50)
);

CREATE TABLE pedidos (
    pedido_id INT PRIMARY KEY,
    cliente_id INT,
    vendedor_id INT,
    data_pedido DATE,
    FOREIGN KEY (cliente_id) REFERENCES clientes(cliente_id),
    FOREIGN KEY (vendedor_id) REFERENCES vendedores(vendedor_id)
);

CREATE TABLE itens_pedido (
    pedido_id INT,
    produto VARCHAR(100),
    quantidade INT,
    PRIMARY KEY (pedido_id, produto),
    FOREIGN KEY (pedido_id) REFERENCES pedidos(pedido_id)
);

6. Benefícios e Desvantagens da Normalização

Benefícios:
- Integridade dos dados: Reduz anomalias de inserção, atualização e exclusão
- Redução de espaço: Elimina redundâncias desnecessárias
- Facilidade de manutenção: Alterações em dados mestre (como endereço do cliente) são feitas em um único local
- Consistência: Garante que dados duplicados não fiquem inconsistentes

Desvantagens:
- Aumento de JOINs: Consultas que antes liam uma única tabela agora exigem múltiplos JOINs
- Impacto em performance de leitura: JOINs adicionais podem tornar consultas mais lentas em grandes volumes
- Complexidade: O esquema pode se tornar mais difícil de entender para iniciantes

Quando normalizar:
- Essencial para sistemas transacionais (OLTP) com muitas operações de escrita
- Pode ser flexibilizada em sistemas de análise (OLAP) ou data warehouses

7. Conclusão e Próximos Passos

A normalização 1NF, 2NF e 3NF forma a base para projetos de banco de dados relacionais robustos. A 1NF elimina grupos repetitivos, a 2NF remove dependências parciais e a 3NF elimina dependências transitivas. O resultado é um esquema que minimiza redundâncias e garante integridade referencial.

Formas normais mais avançadas como BCNF (Boyce-Codd Normal Form) e 4NF (Quarta Forma Normal) tratam de casos específicos de dependências funcionais e multivaloradas, sendo menos comuns na prática.

Nos próximos artigos desta série, abordaremos índices para otimização de consultas e técnicas de desnormalização para cenários de alta performance de leitura.

Referências