Pesquisar conteúdos

Encontre uma trilha ou aula pelo assunto.

Experimente pesquisar por “governança”, “ITIL” ou “planejamento”.

Conteúdo da trilha

Dependências funcionais e normalização: 1FN, 2FN, 3FN e BCNF

Identifique dependências e reorganize tabelas para reduzir redundância e anomalias sem fragmentar o modelo sem necessidade.
Uma relação redundante é analisada por dependências e decomposta em relações menores conectadas por chaves

Normalizar é organizar fatos segundo suas dependências

Depois de transformar o modelo ER em relações, ainda precisamos verificar se cada atributo está armazenado no lugar correto. Uma tabela pode respeitar chaves e referências e, mesmo assim, repetir informações, dificultar inserções e produzir contradições durante atualizações.

Normalização é a análise sistemática dessas relações. Ela usa dependências entre atributos para decompor estruturas problemáticas em relações menores, buscando reduzir redundância e anomalias sem perder os fatos originais.

Normalizar não significa criar o maior número possível de tabelas. Significa justificar cada agrupamento e cada separação.

O problema aparece antes da forma normal

Considere uma relação usada para registrar matrículas no Guia Estudos:

MATRICULA_BRUTA(
  estudante_id,
  estudante_nome,
  trilha_id,
  trilha_titulo,
  instrutor_id,
  instrutor_nome,
  matriculada_em,
  progresso
)

Admita estas regras do domínio:

estudante_id → estudante_nome
trilha_id → trilha_titulo, instrutor_id
instrutor_id → instrutor_nome
(estudante_id, trilha_id) → matriculada_em, progresso

O par (estudante_id, trilha_id) identifica uma matrícula. Entretanto, nome do estudante depende apenas de estudante_id; título e instrutor dependem apenas de trilha_id; nome do instrutor depende de instrutor_id. Uma única linha mistura fatos sobre quatro assuntos.

Anomalia de atualização

Se o nome da trilha aparece em mil matrículas, renomeá-la exige alterar mil linhas. Uma falha parcial deixa títulos diferentes para o mesmo trilha_id.

Anomalia de inserção

Talvez não seja possível cadastrar uma trilha antes da primeira matrícula, porque a linha exige também um estudante. Um fato sobre trilha fica indevidamente condicionado a outro fato.

Anomalia de exclusão

Ao excluir a última matrícula de uma trilha, podemos apagar junto o único registro de seu título e instrutor. Remover um vínculo destrói dados de outra entidade.

Uma relação de matrículas repete estudante, trilha e instrutor; setas mostram como a repetição causa anomalias de inserção, atualização e exclusão
As anomalias são sintomas. A causa está em reunir fatos governados por determinantes diferentes na mesma relação.

Dependência funcional descreve uma regra do domínio

Escrevemos X → Y quando, em toda instância válida da relação, duas tuplas que concordam nos atributos de X também precisam concordar nos atributos de Y. X é o determinante e Y é funcionalmente dependente de X.

trilha_id → trilha_titulo

Isso significa que um identificador de trilha determina um único título naquele estado do banco. O inverso não é automático: duas trilhas podem ter o mesmo título.

Uma dependência é uma afirmação sobre todos os estados permitidos pelo domínio, não uma coincidência da amostra atual. Se hoje cada instrutor aparece em uma única trilha, isso não autoriza concluir instrutor_id → trilha_id quando o negócio permite que um instrutor conduza várias trilhas.

Dependência trivial

{estudante_id, trilha_id} → estudante_id é trivial porque o lado direito já está contido no esquerdo. Ela sempre vale e não revela um problema de projeto.

Dependência total e parcial

Um atributo depende totalmente de uma chave composta quando nenhuma parte própria da chave consegue determiná-lo.

(estudante_id, trilha_id) → progresso

O progresso descreve o par. Já estudante_id → estudante_nome é uma dependência parcial em relação à chave composta: apenas parte dela basta.

Dependência transitiva

Existe um caminho indireto quando:

trilha_id → instrutor_id
instrutor_id → instrutor_nome

Logo, trilha_id → instrutor_nome pode ser inferida por transitividade. O nome é fato do instrutor, não da trilha nem da matrícula.

Fecho de atributos

O fecho de um conjunto X, escrito X⁺, reúne tudo que pode ser determinado por X usando as dependências conhecidas. Ele ajuda a testar se X é uma superchave.

Com as dependências do exemplo:

{estudante_id, trilha_id}⁺ = {
  estudante_id, estudante_nome,
  trilha_id, trilha_titulo,
  instrutor_id, instrutor_nome,
  matriculada_em, progresso
}

Como o fecho alcança todos os atributos, o par é uma superchave. Como nenhum de seus componentes isolados alcança a relação inteira, ele é também uma chave candidata.

Primeira Forma Normal: elimine grupos repetitivos

Uma relação em Primeira Forma Normal (1FN) possui valores atômicos para o uso relacional e não contém grupos repetitivos como telefone_1, telefone_2, telefone_3 ou uma lista de IDs escondida numa célula.

Suponha:

ESTUDANTE(id, nome, interesses)

Se interesses guarda "SQL, Redes, Segurança", o banco não consegue referenciar, validar ou combinar cada interesse como valor independente. A estrutura adequada separa as ocorrências:

ESTUDANTE(id PK, nome)
INTERESSE_ESTUDANTE(id_estudante PK/FK, interesse PK)

“Atômico” depende da operação necessária. Um título pode conter várias palavras e continuar sendo um único valor. Um endereço pode permanecer inteiro se nunca houver regra sobre suas partes; se cidade e estado precisam ser pesquisados ou validados separadamente, esconder tudo em uma string não atende ao modelo.

1FN resolve a estrutura repetitiva, mas não elimina automaticamente redundâncias causadas por dependências parciais ou transitivas.

Segunda Forma Normal: dependa da chave inteira

Uma relação está em Segunda Forma Normal (2FN) quando está em 1FN e todo atributo não primo depende totalmente de cada chave candidata — não apenas de uma parte de uma chave composta.

Na relação MATRICULA_BRUTA, a chave é (estudante_id, trilha_id). Estas dependências violam 2FN:

estudante_id → estudante_nome
trilha_id → trilha_titulo, instrutor_id, instrutor_nome

Separe os fatos determinados por cada parte:

ESTUDANTE(estudante_id PK, estudante_nome)

TRILHA_TEMP(
  trilha_id PK,
  trilha_titulo,
  instrutor_id,
  instrutor_nome
)

MATRICULA(
  estudante_id PK/FK,
  trilha_id PK/FK,
  matriculada_em,
  progresso
)

Agora os atributos de matrícula dependem do par completo. A tabela temporária de trilha ainda possui uma dependência transitiva, que será tratada na etapa seguinte.

Se uma relação possui apenas uma chave candidata simples, não pode haver dependência parcial dessa chave. Portanto, estando em 1FN, ela satisfaz automaticamente esse aspecto da 2FN. Isso não significa que já esteja em 3FN.

Terceira Forma Normal: remova dependências transitivas impróprias

Uma relação está em Terceira Forma Normal (3FN) quando está em 2FN e, para toda dependência funcional não trivial X → A, X é superchave ou A é atributo primo — isto é, participa de alguma chave candidata.

Na forma introdutória mais comum: atributos que não pertencem a chaves não devem depender de outros atributos não-chave.

Em TRILHA_TEMP:

trilha_id → instrutor_id
instrutor_id → instrutor_nome

instrutor_nome depende transitivamente de trilha_id. Separe o fato sobre o instrutor:

TRILHA(
  trilha_id PK,
  trilha_titulo,
  instrutor_id FK
)

INSTRUTOR(
  instrutor_id PK,
  instrutor_nome
)

O esquema em 3FN fica:

ESTUDANTE(estudante_id PK, estudante_nome)
INSTRUTOR(instrutor_id PK, instrutor_nome)
TRILHA(trilha_id PK, trilha_titulo, instrutor_id FK)
MATRICULA(estudante_id PK/FK, trilha_id PK/FK, matriculada_em, progresso)

Cada relação expressa um tipo de fato: estudante, instrutor, trilha ou matrícula. Alterar o nome de um instrutor ocorre em um lugar; cadastrar uma trilha não exige matrícula; excluir uma matrícula não elimina a trilha.

Uma relação bruta avança por 1FN, 2FN e 3FN: grupos repetitivos são separados, dependências parciais saem da matrícula e a dependência transitiva do instrutor ganha relação própria
As formas normais são cumulativas. Cada etapa remove um tipo de problema sem dispensar a verificação das etapas anteriores.

BCNF exige que todo determinante relevante seja superchave

A Forma Normal de Boyce-Codd (BCNF) fortalece a 3FN: para toda dependência funcional não trivial X → Y, X deve ser uma superchave.

Toda relação em BCNF está em 3FN, mas uma relação em 3FN pode não estar em BCNF. A diferença aparece em estruturas com chaves candidatas sobrepostas.

Considere:

ORIENTACAO(estudante, tema, orientador)

(estudante, tema) → orientador
orientador → tema

Admita que cada orientador atua em exatamente um tema e que um estudante pode ter um orientador por tema. As chaves candidatas são (estudante, tema) e (estudante, orientador).

A dependência orientador → tema satisfaz 3FN porque tema é atributo primo, mas viola BCNF porque orientador não é superchave. Uma decomposição possível é:

ORIENTADOR_TEMA(orientador PK, tema)
ESTUDANTE_ORIENTADOR(estudante PK, orientador PK)

BCNF elimina mais fontes de redundância, porém uma decomposição em BCNF pode deixar alguma dependência original verificável somente por junção. Por isso, a decisão formal também considera preservação de dependências.

Decompor exige duas verificações

Separar colunas arbitrariamente pode destruir informação ou criar combinações que nunca existiram. Uma boa decomposição avalia pelo menos duas propriedades.

Junção sem perda

Uma decomposição é sem perda quando a junção natural das relações resultantes reconstrói exatamente os fatos válidos da relação original. “Sem perda” não significa apenas que todas as células foram copiadas: uma decomposição ruim pode gerar tuplas espúrias ao recombinar os dados.

Para uma decomposição binária de R em R1 e R2, uma condição de teste é que os atributos comuns R1 ∩ R2 determinem funcionalmente todos os atributos de R1 ou todos os de R2.

No exemplo 3FN:

TRILHA_TEMP(trilha_id, trilha_titulo, instrutor_id, instrutor_nome)

TRILHA(trilha_id, trilha_titulo, instrutor_id)
INSTRUTOR(instrutor_id, instrutor_nome)

A interseção é instrutor_id, que determina INSTRUTOR. A junção é sem perda sob a dependência declarada.

Preservação de dependências

Uma decomposição preserva dependências quando as dependências originais podem ser garantidas verificando separadamente as relações resultantes, sem precisar juntá-las a cada alteração.

3FN possui algoritmos de síntese que podem oferecer decomposição sem perda e preservação de dependências. BCNF sempre pode ser alcançada com decomposição sem perda, mas não garante preservar todas as dependências. Em casos raros, manter 3FN pode ser uma escolha consciente para tornar uma regra importante diretamente verificável.

Dois caminhos de decomposição são comparados: um preserva a junção e as dependências; outro cria combinações espúrias ou exige junções para verificar uma regra, seguido pela decisão entre 3FN e BCNF
A forma normal não é o único critério. Reconstrução exata e capacidade de garantir as dependências também fazem parte do projeto.

Nem toda repetição é uma violação

Em MATRICULA, estudante_id aparece em várias linhas. Isso é repetição de um identificador para representar vários fatos distintos, não redundância indevida. O problema seria repetir estudante_nome em cada matrícula, pois seu valor é determinado apenas por estudante_id e precisaria ser sincronizado.

Da mesma forma, uma FK repetida no lado N de um relacionamento 1:N é parte natural do modelo. Normalização não tenta eliminar toda ocorrência repetida; elimina a repetição do mesmo fato independente.

Restrições materializam apenas parte da análise

Depois da normalização, implemente as chaves e restrições correspondentes:

CREATE TABLE instrutor (
  instrutor_id bigint PRIMARY KEY,
  nome text NOT NULL
);

CREATE TABLE trilha (
  trilha_id bigint PRIMARY KEY,
  titulo text NOT NULL,
  instrutor_id bigint NOT NULL
    REFERENCES instrutor (instrutor_id)
);

CREATE TABLE matricula (
  estudante_id bigint NOT NULL
    REFERENCES estudante (estudante_id),
  trilha_id bigint NOT NULL
    REFERENCES trilha (trilha_id),
  matriculada_em date NOT NULL,
  progresso numeric(5, 2) NOT NULL
    CHECK (progresso BETWEEN 0 AND 100),
  PRIMARY KEY (estudante_id, trilha_id)
);

PKs, UNIQUE e FKs conseguem impor diversas dependências baseadas em identificadores. Nem toda dependência arbitrária possui uma declaração SQL direta e portátil. Se uma regra não cabe numa constraint simples, documente onde será garantida e como será testada.

Normalização e desempenho são decisões diferentes

Normalização pertence ao projeto lógico. Índices, particionamento, materialização e desnormalização orientada por carga pertencem principalmente ao projeto físico e à operação.

Uma consulta com várias junções não prova que o modelo está “normalizado demais”. Primeiro meça plano de execução, volume, seletividade e frequência. Índices adequados ou outra formulação podem resolver o problema sem duplicar fatos.

Desnormalização é uma decisão consciente de introduzir redundância para atender uma necessidade medida. Ela deve registrar:

  • qual consulta ou carga justifica a duplicação;
  • qual é a fonte autoritativa do fato;
  • como as cópias serão sincronizadas;
  • qual inconsistência é possível durante falhas;
  • como validar e reconstruir os dados;
  • quais métricas confirmarão o benefício.

Erros comuns ao normalizar

  • deduzir dependências apenas pelos dados atuais: coincidências da amostra podem desaparecer amanhã;
  • considerar apenas a chave primária escolhida: formas normais avaliam chaves candidatas e superchaves;
  • dizer que 2FN remove toda dependência indireta: 2FN trata dependências parciais; 3FN trata a transitividade relevante;
  • separar toda coluna repetida: FKs repetidas podem representar fatos diferentes e corretos;
  • criar uma tabela por atributo: decomposição precisa de dependência e significado, não de fragmentação;
  • ignorar junção sem perda: a recomposição pode criar tuplas falsas;
  • afirmar que BCNF é sempre a única resposta: preservação de dependências pode justificar 3FN;
  • desnormalizar por antecipação: desempenho deve ser medido;
  • usar JSON ou listas para escapar da 1FN: o formato não elimina a necessidade de consultar e garantir cada fato;
  • esquecer restrições após decompor: tabelas menores sem PKs, FKs e unicidade não preservam o modelo.

Roteiro prático de normalização

  1. Defina a semântica de cada atributo e o universo válido da relação.
  2. Liste chaves candidatas, não apenas a PK escolhida.
  3. Registre dependências funcionais confirmadas pelo domínio.
  4. Use fechos para conferir superchaves e dependências implícitas.
  5. Identifique anomalias reais de inserção, atualização e exclusão.
  6. Garanta 1FN, removendo grupos repetitivos e valores multivalorados relevantes.
  7. Garanta 2FN, removendo dependências parciais de chaves compostas.
  8. Garanta 3FN, tratando dependências transitivas inadequadas.
  9. Teste BCNF e avalie o custo de qualquer dependência não preservada.
  10. Confirme junção sem perda em toda decomposição.
  11. Materialize chaves, referências, unicidade e domínios no esquema.
  12. Valide operações típicas e casos-limite com dados fictícios.
  13. Meça antes de considerar desnormalização.
  14. Registre decisões e exceções no dicionário de dados.

O que você deve guardar

Dependência funcional é uma regra semântica: valores do determinante fixam valores dos atributos dependentes. As formas normais usam essas regras de maneira cumulativa. A 1FN remove grupos repetitivos; a 2FN elimina dependências parciais de chaves compostas; a 3FN trata dependências transitivas impróprias; a BCNF exige que todo determinante de uma dependência não trivial seja superchave.

Uma decomposição só é útil quando preserva os fatos. Verifique junção sem perda e dependências importantes. Normalize primeiro para obter um modelo lógico compreensível; só introduza redundância depois de medir uma necessidade e definir como manter as cópias consistentes.

Na próxima aula, iniciaremos o módulo com SQL, DDL, DML, DCL e controle de transações, relacionando cada família ao esquema construído até aqui.

Referências