Modelagem de Dados¶
Por que um banco de dados (e não uma planilha)?¶
Uma forma simples de controlar informação (gastos, estoque, clientes, ...) é uma tabela: linhas para cada registro, colunas para cada informação sobre ele. Uma planilha eletrônica resolve isso bem — até o volume de dados crescer, ou até você precisar de relatórios/cálculos mais complexos, consultas rápidas por critério, ou consistência garantida (ex.: dois processos gravando ao mesmo tempo sem conflito).
Definição: SGBD (Sistema de Gerenciamento de Banco de Dados)
Software responsável por armazenar e consultar dados de forma eficiente e segura, sem que a aplicação precise se preocupar com o "como" — só o "o quê" (ver SQL). Exemplos: MySQL, PostgreSQL, Oracle, SQL Server.
Fundamentos de SGBD relacional¶
Da pasta de arquivos ao banco de dados¶
| Abordagem | Como é | Problemas |
|---|---|---|
| Tradicional (arquivos por sistema) | Cada programa tem seus próprios arquivos | Duplicidade de dados, inconsistência, difícil relacionar informações |
| Sistemas integrados | Módulos compartilham dados dentro de um mesmo sistema | Acoplamento forte; mudar um dado exige mexer em vários programas |
| Banco de dados | Dados centralizados e geridos por um SGBD (Sistema Gerenciador de Banco de Dados), independentes dos programas | Exige modelagem e administração |
Vantagens do SGBD: controle de redundância, integridade, segurança e permissões, concorrência (vários usuários), recuperação (backup/restore) e linguagem de consulta padronizada.
Níveis de abstração e independência de dados¶
Definição: abstração de dados
Capacidade de esconder detalhes e mostrar a cada público só o que interessa. A arquitetura clássica (ANSI/SPARC) tem três níveis.
| Nível | Descreve | Quem usa |
|---|---|---|
| Físico (interno) | Como os dados são armazenados (blocos, índices, arquivos) | Administradores de banco |
| Conceitual (lógico) | Quais dados e relações (tabelas, colunas, chaves) | Projetistas e DBAs |
| Visões (externo) | Apenas a parte do banco que cada usuário ou aplicação precisa | Usuários finais e aplicações (views) |
- Esquema é a descrição da estrutura (muda pouco); instância é o conteúdo do banco em um instante (muda sempre).
- Independência física: mudar o armazenamento (índices, discos, particionamento) sem alterar o esquema lógico nem os programas.
- Independência lógica: mudar o esquema lógico (ex.: adicionar colunas) sem quebrar os programas. É mais difícil de alcançar, e as views ajudam.
Linguagens e usuários do SGBD¶
| Sigla | Nome | Para quê | Comandos |
|---|---|---|---|
| DDL | Definição de dados | Criar e alterar a estrutura | CREATE, ALTER, DROP |
| DML | Manipulação de dados | Inserir, alterar, excluir, consultar | INSERT, UPDATE, DELETE, SELECT |
| DCL | Controle de dados | Permissões | GRANT, REVOKE |
| DTL/TCL | Controle de transações | Confirmar ou desfazer | COMMIT, ROLLBACK, SAVEPOINT |
Usuários: DBA (administra, segurança e desempenho), projetistas/analistas (modelam), programadores (aplicações) e usuários finais (consultas e telas).
Modelo relacional: chaves, integridade e conversão¶
- Chaves: primária (identifica a linha), estrangeira (referencia a primária de outra tabela), alternativa/candidata e composta; índices aceleram buscas.
- Regras de integridade: de entidade (a chave primária nunca é nula nem repetida) e referencial (toda chave estrangeira aponta para uma chave existente, ou é nula).
- Do modelo entidade-relacionamento (MER) ao relacional: cada entidade vira uma tabela; relacionamento 1:N coloca a chave estrangeira no lado "N"; N:N vira uma tabela associativa com as duas chaves; 1:1 coloca a chave em um dos lados (ou funde as tabelas); atributo multivalorado vira outra tabela; atributo composto vira colunas (Modelagem).
As regras de Codd¶
Em 1970, Edgar F. Codd propôs o modelo relacional e, depois, 12 regras (mais a regra zero) para um banco verdadeiramente relacional. As mais citadas:
| Regra | Em resumo |
|---|---|
| 0 (fundamento) | O SGBD gerencia os dados apenas por capacidades relacionais |
| 1 (informação) | Toda informação (inclusive os metadados) é representada por valores em tabelas |
| 2 (acesso garantido) | Todo dado é acessível por tabela + chave primária + coluna; a ordem das linhas e colunas não importa |
| 3 (valores nulos) | NULL representa informação inexistente ou desconhecida, tratada de forma sistemática (não é zero nem vazio) |
| 4 (catálogo dinâmico) | O dicionário de dados é armazenado em tabelas e consultável com a mesma linguagem |
| 5 (sublinguagem completa) | Uma linguagem (SQL) cobre definição, manipulação, integridade, autorização e transações |
| 6 (atualização de visões) | Visões teoricamente atualizáveis devem ser atualizáveis pelo sistema |
| 7 (operações de conjunto) | Inserir, alterar e excluir operam sobre conjuntos de linhas |
| 8 e 9 (independência) | Física e lógica de dados |
| 10 (independência de integridade) | Regras de integridade ficam no catálogo, não nos programas |
| 11 (independência de distribuição) | Os dados podem estar distribuídos sem mudar as aplicações |
| 12 (não subversão) | Não se pode burlar regras de integridade por uma linguagem de baixo nível |
Poucos SGBDs cumprem todas, mas elas definem o que se espera de um banco relacional (ACID e transações).
Tabelas, linhas e colunas¶
Um banco de dados relacional organiza dados em tabelas — o mesmo conceito de linhas e colunas de uma planilha, mas com um detalhe crucial: cada coluna tem um tipo de dado declarado (número decimal, data, texto, ...), e o banco garante que ninguém insira um valor incompatível com esse tipo.
Cada linha de uma tabela é um registro — uma ocorrência completa daquela entidade (uma compra, uma pessoa, um pedido, ...).
Chave primária¶
Depois que uma tabela cresce, referenciar uma linha específica por descrição ("aquela compra de lanchonete do dia 5") fica inviável — pode haver várias compras parecidas. É o mesmo problema de identificar uma pessoa (por isso existe o CPF) ou um computador (por isso existe o número de série): precisa de um valor único.
Definição: Chave primária (Primary Key)
Coluna (ou conjunto de colunas) que identifica unicamente cada linha de uma
tabela — nunca se repete, nunca fica vazia. A forma mais simples e comum de gerar
esse valor é um número inteiro que incrementa automaticamente a cada novo
registro (1, 2, 3, ...), convencionalmente chamado de id. Ver SQL
para a sintaxe (PRIMARY KEY, AUTO_INCREMENT).
Modelagem é um processo iterativo, não uma etapa única¶
Modelar uma tabela é decidir quais colunas ela precisa, a partir da conversa com quem
vai usar o sistema — não existe um conjunto de regras fixas que garanta "o modelo
certo" na primeira tentativa. Um exemplo típico: uma tabela de Aluno para uma
escola pode começar simples (id, nome, serie, sala, contato) — mas, ao
conversar com a diretoria, aparecem novas necessidades:
- Precisa contatar os pais, não o aluno → viram novos campos (nome/telefone do pai e da mãe).
- Precisa saber a data de nascimento para decidir vacinação por idade → campo novo.
serieesalamudam todo ano → os nomes dos campos são ajustados para deixar isso explícito (serieAtual,salaAtual), evitando a leitura errada de que são valores fixos.
A lição prática: um modelo de dados evolui conforme você entende melhor o domínio e os requisitos mudam — refinar o modelo depois de identificar uma lacuna não é sinal de que o modelo original estava "errado", é o processo funcionando como esperado.
Exemplo de trade-off: como representar "inativo"?¶
Um bom exercício de modelagem: a escola descobre um bug e percebe que precisa saber
quando um aluno não está mais ativo (saiu da escola). Como representar isso na
tabela Aluno, que tem colunas serieAtual e salaAtual? Três abordagens possíveis,
cada uma com uma consequência diferente:
- Marcar
serieAtual/salaAtualcomoNULLquando o aluno sai. Simples, mas ambíguo: umNULLtambém poderia significar "esqueceram de preencher a série de um aluno novo" — as duas situações (inativo x dado faltando) ficam indistinguíveis. - Usar
NULL(para "sem valor") e um campo separadoativo(booleano). Resolve a ambiguidade do item 1, mas ainda permite estados inconsistentes — nada impede um registro comsalaAtualpreenchida eativo = falseao mesmo tempo (o aluno está na sala ou não está?). - Só o campo
ativo, sem nulos. Mais simples de consultar (WHERE ativo = false), mas permite o mesmo tipo de estado estranho do item 2 (sala preenchida num aluno inativo) — só que agora sem o sinal visual doNULLpara desconfiar.
Definição: Não existe modelagem sem trade-off
As três abordagens resolvem o problema original e criam, cada uma, um problema
técnico diferente. Não há uma resposta certa universal — o que existe é
conhecer as desvantagens de cada opção de antemão, para escolher a que gera menos
dor para o seu caso específico, e não ser pego de surpresa depois. Alguns bancos
oferecem recursos mais avançados para reforçar essas regras (ex.: CHECK em
algumas versões), mas variam de SGBD para SGBD — não são um padrão universal do
SQL.
Normalização: de coluna solta para tabela relacionada¶
Um sinal clássico de que uma tabela precisa ser normalizada (dividida em duas ou
mais tabelas relacionadas): guardar informação de uma outra entidade como colunas
soltas. Por exemplo, uma tabela compras com colunas comprador e telefone
diretamente nela, em vez de numa tabela compradores própria.
O problema não é estético — é de integridade. Guardando o nome do comprador como texto livre repetido em cada compra:
- Inconsistência: nada impede
'João da Silva'numa linha e'joão da silva'(grafia diferente) noutra — para o banco, são dois compradores diferentes, mesmo sendo a mesma pessoa na vida real. - Redundância: o telefone do mesmo comprador é repetido em toda compra dele — se ele troca de telefone, é preciso atualizar todas as suas compras, uma por uma (fácil de esquecer alguma).
A solução: extrair o comprador para sua própria tabela (com sua própria chave
primária), e guardar, na tabela compras, só uma referência a esse comprador — uma
coluna com o id dele:
CREATE TABLE compradores (
id INT PRIMARY KEY AUTO_INCREMENT,
nome VARCHAR(200),
endereco VARCHAR(200),
telefone VARCHAR(30)
);
ALTER TABLE compras ADD COLUMN id_compradores INT;
Definição: Foreign Key (chave estrangeira)
Coluna que guarda o valor da chave primária de outra tabela, criando um
relacionamento entre as duas. Ver SQL para a constraint que
faz o banco impor essa regra sozinho (FOREIGN KEY ... REFERENCES ...).
Formas normais: 1FN, 2FN e 3FN¶
Normalizar é organizar o banco para reduzir repetições e inconsistências dividindo as informações em tabelas relacionadas. As formas normais são regras progressivas — cada uma pressupõe a anterior. Cuidado: normalizar sem perder a clareza do modelo.
| Forma | Regra | Problema que resolve |
|---|---|---|
| 1FN | Cada campo guarda um único valor (valores atômicos); uma coluna não contém listas; cada linha é identificada por uma chave primária | Coluna telefones com '9999, 8888' |
| 2FN | Já está em 1FN e cada dado depende da chave completa (relevante com chave composta) | Em itens_pedido(pedido_id, produto_id, nome_produto), nome_produto depende só de produto_id |
| 3FN | Já está em 2FN e não há dependência entre colunas não-chave | cidade depende de cep, e não diretamente do cliente |
Como resolver:
- 1FN: criar uma tabela separada para os valores repetidos (ex.: tabela
telefonescomcliente_idetelefone, uma linha por telefone). - 2FN: mover o dado para a tabela que representa a entidade a que ele pertence (ex.:
nome_produtovai paraprodutos). - 3FN: criar uma tabela própria para a informação relacionada (ex.: tabela de
cepcomcidade), de modo que cada fato seja armazenado em um só lugar.
Benefícios: atualizações mais simples e seguras, menos repetição e menor risco de inconsistência. (Exemplo prático da primeira etapa em Normalização: de coluna solta para tabela relacionada.)
One to Many / Many to One: de que lado fica a Foreign Key?¶
Um comprador pode ter várias compras; uma compra pertence a um único comprador. É essa assimetria — vista de um lado é "um para muitos" (one to many), vista do outro é "muitos para um" (many to one) — que determina de que lado a chave estrangeira deve ficar.
Definição: A Foreign Key sempre fica no lado 'muitos'
Regra prática que resolve a confusão de "quem referencia quem": a coluna de chave
estrangeira vive na tabela que representa o lado "muitos" da relação
(compras.id_compradores, referenciando compradores.id) — nunca o contrário.
Colocar o id da compra dentro de compradores obrigaria cada comprador a ter no
máximo uma compra (uma única coluna só guarda um valor por vez), o que
contradiz a realidade que estamos modelando.
Many to Many: quando nenhum dos dois lados basta¶
Nem toda relação é "um para muitos". Considere alunos e cursos: um aluno pode se
matricular em vários cursos, e um curso tem vários alunos matriculados. Não dá
para colocar a chave estrangeira só de um lado — nenhuma tabela sozinha (aluno nem
curso) tem como guardar "vários valores" numa única coluna.
A solução padrão é uma tabela associativa (ou tabela de junção): uma terceira tabela, cuja única (ou principal) função é guardar pares de chaves estrangeiras, uma para cada lado da relação:
CREATE TABLE matricula (
id INT PRIMARY KEY AUTO_INCREMENT,
aluno_id INT NOT NULL,
curso_id INT NOT NULL,
data DATETIME NOT NULL,
-- FOREIGN KEY (aluno_id) REFERENCES aluno (id),
-- FOREIGN KEY (curso_id) REFERENCES curso (id)
);
Cada linha de matricula representa uma matrícula específica — um aluno
específico, num curso específico. Um mesmo aluno aparece em várias linhas (uma por
curso em que está matriculado), e um mesmo curso também aparece em várias linhas (uma
por aluno matriculado nele) — é assim que a tabela associativa viabiliza o "muitos
para muitos" sem duplicar dado nenhum de aluno ou curso.