curso
Normalização em SQL (1NF - 5NF): Um guia para iniciantes
Neste artigo, exploraremos os conceitos básicos que você precisa saber sobre normalização, sua importância e as várias técnicas envolvidas. Este artigo é para, mas não se limita a, aqueles que desejam entrar no setor de dados.
O que é normalização no SQL?
A normalização, nesse contexto, é o processo de organização de dados em um banco de dados(banco de dados relacional) para eliminar anomalias de dados, como redundância.
Em termos mais simples, isso envolve a divisão de uma tabela grande e complexa em tabelas menores e mais simples, mantendo as relações de dados.
A normalização é comumente usada ao lidar com grandes conjuntos de dados.
Vamos dar uma breve olhada em alguns cenários em que a normalização é usada com frequência.
Integridade dos dados
Imagine um banco de dados que contém informações de clientes. Sem a normalização, se um cliente mudasse sua idade, precisaríamos atualizá-la em vários lugares, o que aumentaria o risco de inconsistências. Ao normalizar os dados, podemos ter tabelas separadas vinculadas por um identificador exclusivo que garantirá que os dados permaneçam precisos e consistentes.
Consulta de eficiência
Vamos considerar um banco de dados complexo com várias tabelas relacionadas que armazenam informações redundantes. Nesse cenário, as consultas que envolvem uniões se tornam mais complicadas e consomem muitos recursos. A normalização ajudará a simplificar a consulta, dividindo os dados em tabelas menores, com cada tabela contendo apenas informações relevantes, reduzindo assim a necessidade de uniões complexas.
Otimização do armazenamento
Um dos principais problemas dos dados redundantes é que eles ocupam espaço de armazenamento desnecessário. Por exemplo, se armazenarmos os mesmos detalhes do produto em cada registro de pedido, isso levará à duplicação. Com a normalização, você pode eliminar a redundância dividindo os dados em tabelas separadas.
Por que a normalização no SQL é importante?
A normalização desempenha um papel fundamental no design do banco de dados. Aqui estão vários motivos pelos quais isso é essencial:
- Reduz a redundância: Redundância é quando a mesma informação é armazenada várias vezes, e uma boa maneira de evitar isso é dividir os dados em tabelas menores.
- Melhora o desempenho da consulta: Você pode executar consultas mais rapidamente em tabelas menores que passaram por normalização.
- Minimiza as anomalias de atualização: Com tabelas normalizadas, você pode atualizar facilmente os dados sem afetar outros registros.
- Melhora a integridade dos dados: Isso garante que os dados permaneçam consistentes e precisos.
O que causa a necessidade de normalização?
Se uma tabela não estiver adequadamente normalizada e tiver redundância de dados, ela não só ocupará espaço extra de armazenamento de dados, mas também dificultará o manuseio e a atualização do banco de dados.
Há vários fatores que impulsionam a necessidade de normalização, desde a redundância de dados (conforme abordado acima) até a dificuldade de gerenciar relacionamentos. Vamos direto ao assunto:
- Anomalias de inserção, exclusão e atualização: Qualquer forma de alteração em uma tabela pode levar a erros ou inconsistências em outras tabelas se você não for tratado com cuidado. Essas alterações podem ser a adição de novos dados a um banco de dados, a atualização dos dados ou a exclusão de registros, o que pode levar à perda não intencional de dados.
- Dificuldade em gerenciar relacionamentos: Torna-se mais desafiador manter relacionamentos complexos em uma estrutura não normalizada.
- Outros fatores que impulsionam a necessidade de normalização são as dependências parciais e as dependências transitivas, nas quais as dependências parciais podem levar à redundância de dados e a anomalias de atualização, e as dependências transitivas podem levar a anomalias de dados. Nas próximas seções, veremos como essas dependências podem ser tratadas para garantir a normalização do banco de dados.
Diferentes tipos de normalização de banco de dados
Até agora, vimos o que é normalização em SQL, por que a normalização em SQL é importante e o que causa a necessidade de normalização. A normalização do banco de dados vem em diferentes formas, cada uma com níveis crescentes de organização de dados.
Nesta seção, discutiremos brevemente os diferentes níveis de normalização e, em seguida, os exploraremos mais profundamente na próxima seção.
Imagem do autor
Primeira forma normal (1NF)
Esse nível de normalização garante que cada coluna dos seus dados contenha apenas valores atômicos. Valores atômicos, nesse contexto, significam que cada entrada em uma coluna é indivisível. É como dizer que cada célula de uma planilha deve conter apenas uma informação. O 1NF garante a atomicidade dos dados, com cada célula de coluna contendo apenas um único valor e cada coluna com nomes exclusivos.
Segunda forma normal (2NF)
Elimina dependências parciais, garantindo que os atributos que não são chaves dependam apenas da chave primária. O que isso significa, em essência, é que deve haver uma relação direta entre cada coluna e a chave primária, e não entre outras colunas.
Terceira forma normal (3NF)
Remove as dependências transitivas, garantindo que os atributos que não são chaves dependam apenas da chave primária. Esse nível de normalização se baseia em 2NF.
Forma Normal de Boyce-Codd (BCNF)
Essa é uma versão mais rigorosa do 3NF que aborda outras anomalias. Nesse nível de normalização, cada determinante é uma chave candidata.
Quarta forma normal (4NF)
Esse é um nível de normalização que se baseia no BCNF, lidando com dependências multivaloradas.
Quinta Forma Normal (5NF)
O 5NF é o nível de normalização mais alto que aborda as dependências de união. Ele é usado em cenários específicos para minimizar ainda mais a redundância, dividindo uma tabela em tabelas menores.
Normalização de banco de dados com exemplos do mundo real
Já destacamos todos os níveis de normalização de dados. Vamos explorar cada um deles com mais profundidade, com exemplos e explicações.
Normalização da primeira forma normal (1NF)
O 1NF garante que cada célula da coluna contenha apenas valores atômicos. Imagine um banco de dados de biblioteca com uma tabela que armazena informações sobre livros (título, autor, gênero e borrowed_by). Se a tabela não estiver normalizada, borrowed_by poderá conter uma lista de nomes de mutuários separados por vírgulas. Isso viola o 1NF, pois uma única célula contém vários valores. A tabela abaixo é uma boa representação de uma tabela que viola 1NF, conforme descrito anteriormente.
título |
autor |
genre |
emprestado_por |
Para matar um pássaro |
Harper Lee |
Ficção |
John Doe, Jane Doe, James Brown |
O Senhor dos Anéis |
J. R. R. Tolkien |
Fantasia |
Emily Garcia, David Lee |
Harry Potter e a Pedra Filosofal |
J.K. Rowling |
Fantasia |
Michael Chen |
A solução?
No 1NF, criamos uma tabela separada para os mutuários e os vinculamos à tabela de livros. Essas tabelas podem ser vinculadas usando a chave estrangeira na tabela do mutuário ou uma tabela de vinculação separada. A chave estrangeira na abordagem da tabela de mutuários envolve a adição de uma coluna de chave estrangeira à tabela de mutuários que faz referência à chave primária da tabela de livros. Isso imporá uma relação entre as tabelas, garantindo a consistência dos dados.
Você pode encontrar uma representação disso abaixo:
Tabela de livros
book_id (PK) |
título |
autor |
genre |
1 |
Para matar um pássaro |
Harper Lee |
Ficção |
2 |
O Senhor dos Anéis |
J. R. R. Tolkien |
Fantasia |
3 |
Harry Potter e a Pedra Filosofal |
J.K. Rowling |
Fantasia |
Tabela de mutuários
borrower_id (PK) |
nome |
book_id (FK) |
1 |
John Doe |
1 |
2 |
Jane Doe |
1 |
3 |
James Brown |
1 |
4 |
Emily Garcia |
2 |
5 |
David Lee |
2 |
6 |
Michael Chen |
3 |
Segunda forma normal (2NF)
Esse nível de normalização, conforme já descrito, baseia-se no 1NF, garantindo que não haja dependências parciais na chave primária. Em termos mais simples, todos os atributos que não são chaves devem depender de toda a chave primária e não apenas de parte dela.
A partir do 1NF que foi implementado, já temos duas tabelas separadas (você pode verificar a seção 1NF).
Agora, digamos que você queira vincular essas tabelas para registrar os empréstimos. A abordagem inicial pode ser simplesmente adicionar uma coluna borrower_id à tabela de livros, como mostrado abaixo:
book_id (PK) |
título |
autor |
genre |
borrower_id (FK) |
1 |
Para matar um pássaro |
Harper Lee |
Ficção |
1 |
2 |
O Senhor dos Anéis |
J. R. R. Tolkien |
Fantasia |
NULL |
3 |
Harry Potter e a Pedra Filosofal |
J.K. Rowling |
Fantasia |
6 |
Isso pode parecer uma solução, mas viola o 2NF simplesmente porque o borrower_id depende apenas parcialmente do book_id. Um livro pode ter vários tomadores de empréstimo, mas um único borrower_id só pode ser vinculado a um livro nessa estrutura. Isso cria uma dependência parcial.
A solução?
Precisamos obter o relacionamento muitos-para-muitos entre livros e tomadores de empréstimos para obter 2NF. Você pode fazer isso introduzindo uma tabela separada:
Tabela Book_borrowings
borrowing_id (PK) | book_id (FK) | borrower_id (FK) | borrowed_date |
---|---|---|---|
1 | 1 | 1 | 2024-05-04 |
2 | 2 | 4 | 2024-05-04 |
3 | 3 | 6 | 2024-05-04 |
Essa tabela estabelece uma relação clara entre livros e tomadores de empréstimos. O book_id e o borrower_id funcionam como chaves estrangeiras, fazendo referência às chaves primárias em suas respectivas tabelas. Essa abordagem garante que o borrower_id dependa de toda a chave primária (book_id) da tabela books, em conformidade com 2NF.
Terceira forma normal (3NF)
O 3NF baseia-se no 2NF, eliminando as dependências transitivas. Uma dependência transitiva ocorre quando um atributo não-chave depende de outro atributo não-chave, que, por sua vez, depende da chave primária. Basicamente, seu significado vem da lei transitiva.
Com base no 2NF que já implementamos, há três tabelas em nosso banco de dados de bibliotecas:
Tabela de livros
book_id (PK) |
título |
autor |
genre |
1 |
Para matar um pássaro |
Harper Lee |
Ficção |
2 |
O Senhor dos Anéis |
J. R. R. Tolkien |
Fantasia |
3 |
Harry Potter e a Pedra Filosofal |
J.K. Rowling |
Fantasia |
Tabela de mutuários
borrower_id (PK) |
nome |
book_id (FK) |
1 |
John Doe |
1 |
2 |
Jane Doe |
1 |
3 |
James Brown |
1 |
4 |
Emily Garcia |
2 |
5 |
David Lee |
2 |
6 |
Michael Chen |
3 |
Tabela Book_borrowings
borrowing_id (PK) |
book_id (FK) |
borrower_id (FK) |
borrowed_date |
1 |
1 |
1 |
2024-05-04 |
2 |
2 |
4 |
2024-05-04 |
3 |
3 |
6 |
2024-05-04 |
A estrutura 2NF parece eficiente, mas pode haver uma dependência oculta. Imagine que você adicione uma coluna due_date à tabela de livros. Isso pode parecer lógico à primeira vista, mas criará uma dependência transitiva em que você pode ter que se preocupar com o que está acontecendo:
- A coluna due_date depende do borrowing_id (um atributo não-chave) da tabela book_borrowings.
- O borrowing_id, por sua vez, depende do book_id (a chave primária) da tabela books.
A implicação disso é que due_date depende de um atributo intermediário não-chave (borrowing_id) em vez de depender diretamente da chave primária (book_id). Isso viola o 3NF.
A solução?
Você pode mover a coluna due_date para a tabela mais apropriada, atualizando a tabela book_borrowings para incluir as colunas due_date e returned_date.
Abaixo você encontra a tabela atualizada:
borrowing_id (PK) |
book_id (FK) |
borrower_id (FK) |
borrowed_date |
due_date |
1 |
1 |
1 |
2024-05-04 |
2024-05-20 |
2 |
2 |
4 |
2024-05-04 |
2024-05-18 |
3 |
3 |
6 |
2024-05-04 |
2024-05-10 |
Ao colocar a coluna due_date na tabela book_borrowing, você eliminou com sucesso a dependência transitiva.
Isso significa que a due_date agora depende diretamente da relação combinada entre book_id e borrower_id. Nesse contexto, book_id e borrower_id estão agindo como uma chave estrangeira composta, que, juntos, formam a chave primária da tabela book_borrowings.
Forma Normal de Boyce-Codd (BCNF)
O BCNF é baseado em dependências funcionais que consideram todas as chaves candidatas em um relacionamento.
As dependências funcionais (FD) definem as relações entre os atributos em um banco de dados relacional. Um FD afirma que o valor de uma coluna determina o valor de outra coluna relacionada. Os FDs são muito importantes porque orientam o processo de normalização, identificando dependências e garantindo que os dados sejam distribuídos adequadamente pelas tabelas.
BCNF é uma versão mais rígida de 3NF. Isso garante que todo determinante (um conjunto de atributos que identificam exclusivamente uma linha) em uma tabela seja uma chave candidata (um conjunto mínimo de atributos que identificam exclusivamente uma linha). A essência disso é que todos os determinantes devem ser capazes de servir como chaves primárias.
Isso garante que cada dependência funcional (FD) tenha uma superchave como seu determinante. Em outras palavras, se X -> Y (X determina Y) for válido, X deverá ser uma chave candidata (superchave) da relação. Observe que X e Y são colunas em uma tabela de dados.
Como um acréscimo do 3NF, temos três tabelas:
Tabela de livros
book_id (PK) |
título |
autor |
genre |
1 |
Para matar um pássaro |
Harper Lee |
Ficção |
2 |
O Senhor dos Anéis |
J. R. R. Tolkien |
Fantasia |
3 |
Harry Potter e a Pedra Filosofal |
J.K. Rowling |
Fantasia |
Tabela de mutuários
borrower_id (PK) |
nome |
book_id (FK) |
1 |
John Doe |
1 |
2 |
Jane Doe |
1 |
3 |
James Brown |
1 |
4 |
Emily Garcia |
2 |
5 |
David Lee |
2 |
6 |
Michael Chen |
3 |
Tabela Book_borrowings
borrowing_id (PK) |
book_id (FK) |
borrower_id (FK) |
borrowed_date |
due_date |
1 |
1 |
1 |
2024-05-04 |
2024-05-20 |
2 |
2 |
4 |
2024-05-04 |
2024-05-18 |
3 |
3 |
6 |
2024-05-04 |
2024-05-10 |
Embora a estrutura 3NF seja boa, pode haver um determinante oculto na tabela book_borrowings. Supondo que um mutuário não possa pegar o mesmo livro duas vezes ao mesmo tempo, a combinação de book_id e borrower_id identifica exclusivamente um registro de empréstimo.
Essa estrutura viola a BCNF, pois o conjunto combinado (book_id e borrower_id) não é a chave primária da tabela (que é apenas borrowing_id).
A solução?
Para obter o BCNF, podemos decompor a tabela book_borrowings em duas tabelas separadas ou tornar o conjunto de atributos combinados a chave primária.
- Abordagem 1 (decompor a tabela): Nessa abordagem, decomporemos a tabela book_borrowings em tabelas separadas:
-
- Uma tabela com borrowing_id como chave primária, borrowed_date, due_date e returned_date.
- Outra tabela separada para vincular livros e tomadores de empréstimo, com book_id como chave estrangeira, borrower_id como chave estrangeira e atributos potencialmente adicionais específicos do evento de empréstimo.
- Abordagem 2 (tornar o conjunto de atributos combinados a chave primária): Podemos considerar a possibilidade de tornar book_id e borrower_id uma chave primária composta para identificar exclusivamente os registros de empréstimos. O problema com essa abordagem é que ela não servirá ao seu propósito se um mutuário puder pegar o mesmo livro emprestado várias vezes.
No final, a escolha entre essas opções depende das suas necessidades específicas de dados e de como você deseja modelar os relacionamentos de empréstimo.
Quarta forma normal (4NF)
O 4NF lida com dependências multivaloradas. Existe uma dependência multivalorada quando um atributo pode ter vários atributos dependentes, e esses atributos dependentes são independentes da chave primária. É bastante complexo, mas vamos explorá-lo mais profundamente usando um exemplo.
O exemplo de biblioteca que usamos ao longo destas explicações não se aplica a esse nível de normalização. Normalmente, a 4NF se aplica a situações em que um único atributo pode ter vários atributos dependentes que não se relacionam diretamente com a chave primária.
Vamos usar outro cenário. Imagine um banco de dados que armazena informações sobre publicações. Vamos considerar uma tabela "Publications" (Publicações) com colunas, título, autor, ano_de_publicação e palavras-chave.
publication_id (PK) |
título |
autor |
publication_year |
palavras-chave |
1 |
Para matar um pássaro |
Harper Lee |
1960 |
Crescimento, Jurídico |
2 |
O Senhor dos Anéis |
J. R. R. Tolkien |
1954 |
Fantasia, épico, aventura |
3 |
Orgulho e Preconceito |
Jane Austen |
1813 |
Romance, comentário social |
A estrutura da tabela acima está violando o 4NF porque:
- A coluna de palavras-chave tem uma dependência de vários valores da chave primária publication_id. Isso significa que uma publicação pode ter várias palavras-chave, e essas palavras-chave são independentes do identificador exclusivo da publicação.
A solução?
Você pode criar uma tabela separada.
Tabela Publication_keywords
publication_id (FK) |
palavra-chave |
1 |
Entrada na idade adulta |
1 |
Legal |
2 |
Fantasia |
2 |
Épico |
2 |
Aventura |
3 |
Romance |
3 |
Comentário social |
A tabela recém-criada (Publication_keywords) estabelece uma relação de muitos para muitos entre a publicação e as palavras-chave. Cada publicação pode ter várias palavras-chave vinculadas por meio de publication_id, que é uma chave estrangeira, e cada palavra-chave pode ser associada a várias publicações.
Com isso, eliminamos com sucesso a dependência multivalorada e obtivemos 4NF.
Quinta Forma Normal (5NF)
5NF é a forma mais complexa de normalização que elimina as dependências de junção. Essa é uma situação em que os dados precisam ser unidos a partir de várias tabelas para responder a uma consulta específica, mesmo quando essas tabelas já estão em 4NF.
Em termos mais simples, o 5NF garante que, ao unir as tabelas, você não poderá obter informações adicionais que ainda não estejam disponíveis nas tabelas separadas.
É menos provável que ocorram dependências de união quando as tabelas já estão normalizadas (em 3NF ou 4NF), daí a dificuldade de criar um exemplo claro e direto para 5NF.
No entanto, vamos dar uma olhada nesse cenário em que o 5NF pode ser relevante:
Imagine um banco de dados universitário com tabelas normalizadas para "Cursos" e "Matrículas".
Tabela de cursos
course_id (PK) |
course_name |
departamento |
101 |
Introdução à programação |
Ciência da Computação |
202 |
Estruturas de dados e algoritmos |
Ciência da Computação |
301 |
Desenvolvimento Web I |
Ciência da Computação |
401 |
Inteligência Artificial |
Ciência da Computação |
Tabela de registros
enrollment_id (PK) |
student_id (FK) |
course_id (FK) |
grau |
1 |
12345 |
101 |
A |
2 |
12345 |
202 |
B |
3 |
56789 |
301 |
A- |
4 |
56789 |
401 |
B+ |
Supondo que essas tabelas já estejam em 3NF ou 4NF, pode haver uma dependência de união, dependendo de como os dados são armazenados. Por exemplo, um curso tem um requisito de pré-requisito armazenado na tabela "Cursos" como a coluna "prerequisite_course_id".
À primeira vista, isso pode parecer eficiente. No entanto, considere uma consulta que precise recuperar os cursos matriculados de um aluno e seus respectivos pré-requisitos. Nesse cenário, você precisaria unir as tabelas "Courses" (Cursos) e "Enrollments" (Matrículas) e, em seguida, possivelmente unir a tabela "Courses" (Cursos) para recuperar informações de pré-requisito.
A solução?
Para potencialmente eliminar a dependência de junção e obter 5NF, poderíamos introduzir uma tabela separada de "Pré-requisitos do curso":
Tabela de pré-requisitos do curso
course_id (FK) |
prerequisite_course_id (FK) |
202 |
101 |
301 |
NULL |
401 |
202 |
Essa abordagem separa as informações de pré-requisitos e permite a recuperação eficiente dos cursos inscritos e seus pré-requisitos em uma única união entre as tabelas "Enrollments" e "Course_prerequisites".
Observação: Estamos presumindo que um aluno só pode ter um pré-requisito por curso.
O 5NF é um tipo de normalização muito complexo e raro, portanto, como alguém que está iniciando sua jornada de aprendizado em dados, talvez você não encontre uma aplicação. No entanto, será um conhecimento adicional que o deixará preparado quando você se deparar com bancos de dados complexos.
Desenvolva suas habilidades em SQL
Se você está lendo isso, parabéns por ter ficado até o fim. Foi um ótimo passeio explorar o que é normalização em SQL, por que a normalização em SQL é importante, o que causa a necessidade de normalização e os diferentes tipos de normalização de banco de dados. Os cenários usados para explicar os diferentes tipos de normalização servem para que você possa entender completamente e também aplicar esse conhecimento em sua jornada de aprendizado.
A normalização é uma habilidade fundamental para qualquer pessoa que esteja iniciando sua carreira em qualquer caminho profissional relacionado a dados. Ao compreender esses princípios, você está pronto para criar bancos de dados eficientes e bem organizados.
O aprendizado é muito importante no espaço de dados e, para que você aprimore suas habilidades em SQL, temos alguns recursos para você.
Perguntas frequentes
O que é normalização no DBMS?
A normalização de banco de dados é uma técnica que projeta de forma ideal o esquema de um banco de dados relacional. Isso envolve a divisão de tabelas em subtabelas menores e o armazenamento de ponteiros para dados em vez de replicá-los.
Por que a normalização é importante?
A normalização ajuda a evitar a redundância de dados, melhora a integridade dos dados e simplifica a manipulação de dados em um banco de dados.
Preciso normalizar meu banco de dados para 5NF?
Não necessariamente. A normalização 3NF ou 4NF geralmente é suficiente para a maioria dos bancos de dados. O 5NF é a forma mais rigorosa e pode ser útil para bancos de dados complexos com padrões de consulta específicos.
Como posso decidir se preciso normalizar para 5NF?
Analise cuidadosamente suas consultas e o modelo de dados. Se você precisar unir várias tabelas para recuperar informações que podem ser teoricamente derivadas das próprias tabelas separadas, talvez valha a pena considerar o 5NF. No entanto, sempre pese a complexidade em relação aos possíveis ganhos de desempenho. Você pode consultar a seção 5NF, onde um cenário de caso foi usado para obter mais entendimento.
Continue sua jornada SQL hoje mesmo!
curso
Joining Data in SQL
curso
Exploratory Data Analysis in SQL
blog
O que é um banco de dados gráfico? Um guia para iniciantes
blog
O que é SQL? - A linguagem essencial para o gerenciamento de bancos de dados
Summer Worsley
16 min
tutorial
Tutorial de visão geral do banco de dados SQL
DataCamp Team
3 min
tutorial
SELEÇÃO de várias colunas no SQL
DataCamp Team
3 min
tutorial
Tutorial do MySQL: Um guia abrangente para iniciantes
tutorial
Como usar um alias SQL para simplificar suas consultas
Allan Ouko
9 min