Projetando Chaves Estrangeiras e Relacionamentos do Jeito Certo
Chaves estrangeiras são a espinha dorsal dos bancos de dados relacionais. Aprenda sobre relacionamentos um-para-um, um-para-muitos e muitos-para-muitos, regras de cascata e armadilhas comuns a evitar.
Chaves estrangeiras são o que torna os bancos de dados relacionais realmente relacionais. Elas garantem a integridade referencial — assegurando que uma linha em uma tabela sempre aponte para uma linha válida em outra. Acertar as chaves estrangeiras é uma das decisões mais impactantes no design do seu schema.
O Básico
Uma chave estrangeira é uma coluna (ou conjunto de colunas) em uma tabela que referencia a chave primária de outra tabela. Quando você diz "cada pedido pertence a um usuário", está definindo uma chave estrangeira: orders.user_id referencia users.id.
O banco de dados impõe essa restrição automaticamente. Você não pode inserir um pedido com um user_id que não existe na tabela users, e não pode deletar um usuário que ainda tem pedidos (a menos que você configure regras de cascata).
Relacionamentos Um-para-Muitos
Este é o tipo de relacionamento mais comum. Um usuário tem muitos pedidos. Um post de blog tem muitos comentários. Um departamento tem muitos funcionários. O padrão é sempre o mesmo: o lado "muitos" recebe uma coluna de chave estrangeira apontando para o lado "um".
No ER Flow, você cria isso adicionando uma coluna como user_id à tabela orders e desenhando uma linha de relacionamento. A ferramenta cuida da restrição de FK para você.
Relacionamentos Um-para-Um
Relacionamentos um-para-um são menos comuns, mas úteis para dividir os dados de uma tabela por razões de privacidade, performance ou organização. Por exemplo, uma tabela users pode ter uma tabela separada user_profiles com informações estendidas.
Para garantir o um-para-um, adicione uma restrição UNIQUE na coluna de chave estrangeira. Isso garante que cada usuário possa ter no máximo um perfil.
Relacionamentos Muitos-para-Muitos
Quando ambos os lados podem ter múltiplos registros relacionados — alunos e cursos, usuários e papéis, produtos e categorias — você precisa de uma tabela de junção. Essa tabela tem duas chaves estrangeiras, uma para cada lado, e sua chave primária é tipicamente a combinação de ambas.
Por exemplo: enrollments com student_id e course_id. Você pode adicionar colunas extras à tabela de junção, como enrolled_at ou grade.
Regras de Cascata
O que acontece quando você deleta um usuário que tem pedidos? A cláusula ON DELETE controla esse comportamento:
CASCADE: Deletar o usuário deleta automaticamente todos os seus pedidos. Use para dados verdadeiramente dependentes (por exemplo, deletar um post deleta seus comentários).
SET NULL: Deletar o usuário define user_id como NULL nos seus pedidos. Use quando o filho pode existir de forma independente.
RESTRICT (padrão): Impede a exclusão completamente. Você precisa deletar ou reatribuir os pedidos primeiro. Esse é o padrão mais seguro.
Armadilhas Comuns
Referências circulares: A Tabela A referencia a Tabela B, que referencia a Tabela A. Isso torna inserções e exclusões complicadas. Evite se possível; se necessário, torne um lado anulável.
Índices ausentes: Colunas de chave estrangeira quase sempre devem ser indexadas. Sem um índice, consultas JOIN e operações CASCADE podem ser extremamente lentas em tabelas grandes.
Excesso de referências: Nem todo relacionamento precisa de uma restrição de chave estrangeira. Se você está referenciando dados entre microsserviços ou sistemas externos, uma coluna de ID simples (sem restrição de FK) é frequentemente mais prático.
No ER Flow, os relacionamentos são criados visualmente. Você pode ver cada chave estrangeira, entender a cardinalidade de relance e configurar as regras de cascata — tudo sem escrever SQL.