Você realmente precisa de chaves estrangeiras?

A decisão de impor restrições de chave estrangeira em bancos relacionais opõe integridade de dados e manutenibilidade de longo prazo a desempenho de escrita, flexibilidade de sharding e complexidade de migração. Muitos engenheiros argumentam que as restrições devem ser o padrão porque evitam bugs sutis, documentam o modelo de dados e protegem dados que sobreviverão a qualquer aplicação individual, enquanto outros apontam grandes implantações em MySQL e arquiteturas especializadas onde as restrições são removidas e a integridade é imposta no código da aplicação. A discussão destaca que chaves estrangeiras raramente são um gargalo em escalas típicas, e que optar por omiti-las com segurança exige alta disciplina, ferramentas robustas e uma compreensão clara das compensações.

Posição geral sobre restrições de chave estrangeira

  • Visão majoritária forte: use restrições de chave estrangeira (FK) por padrão em qualquer sistema não trivial e de longa duração.
  • Elas evitam dados corrompidos/orfãos, expõem bugs da aplicação cedo e tornam refatorações mais seguras.
  • Vários relatos de grandes sistemas legados em MySQL / com centenas de tabelas sem FKs se transformando em pesadelos de “data rot”, exigindo scripts frágeis de limpeza e conhecimento institucional.

Integridade de dados, segurança e documentação

  • FKs são comparadas a tipos, cintos de segurança ou memória protegida: você pode programar sem elas, mas elas detectam muitos erros de forma barata.
  • Com restrições fortes, equipes podem assumir “se está no banco, é válido”, tratando o banco como uma fortaleza.
  • FKs fornecem documentação viva do modelo de dados; FKs ausentes dificultam entender relacionamentos ou até saber se uma coluna é uma referência.

Desempenho, escala e quando considerar remover FKs

  • Críticos argumentam que FKs desaceleram cargas pesadas de escrita/exclusão, complicam sharding e mudanças de esquema online (especialmente no MySQL) e adicionam contenção de locks.
  • Outros respondem que:
    • A maioria dos aplicativos nunca atinge uma escala em que isso importe.
    • Você paga o custo de integridade em algum lugar; mover as verificações para o código da aplicação não as torna gratuitas e introduz risco de races.
    • Processamento em lote, restrições adiadas e ajustes de configuração muitas vezes mitigam problemas de desempenho.
  • Algumas plataformas de altíssima escala ou complexas implementam camadas personalizadas de integridade em vez de FKs nativas, mas isso é apresentado como uma escolha avançada e especializada.

Enforcement no nível da aplicação vs no nível do banco

  • Um grupo: a integridade pode ser imposta na camada da aplicação ou do serviço, especialmente se houver apenas um writer e controle de acesso rígido; FKs são opcionais.
  • Grupo oposto: múltiplos aplicativos, acesso ad hoc e semântica de concorrência tornam frágil e propenso a erros reproduzir garantias do banco em código.

Soft deletes e comportamento de exclusão

  • Combinar soft deletes com deleted_at e FKs é complicado, especialmente para garantir que pais com filhos ativos não possam ser soft-deletados.
  • Abordagens propostas: soft-delete universal, FKs compostas incluindo uma flag “is_deleted”, mover linhas excluídas para tabelas separadas ou tabelas de auditoria via triggers.

Estratégias de ambiente

  • Alguns sugerem habilitar FKs apenas em dev/test para pegar problemas, desabilitando em produção para velocidade de ingestão.
  • Isso é fortemente criticado como invertido e arriscado: produção, e não teste, contém os dados que realmente importam.