it-swarm-pt.tech

O que há de errado com chaves estrangeiras?

Eu me lembro de ouvir Joel Spolsky mencionar em podcast 014 que ele quase nunca usou uma chave estrangeira (se bem me lembro). No entanto, para mim, eles parecem bastante importantes para evitar duplicação e problemas subseqüentes de integridade de dados em todo o banco de dados.

As pessoas têm algumas razões sólidas por que (para evitar uma discussão em linhas com os princípios do Stack Overflow)?

Edit: "Eu ainda tenho que ter uma razão para criar uma chave estrangeira, então esta pode ser minha primeira razão para realmente configurar um. "

246
ljs

Razões para usar chaves estrangeiras:

  • você não terá linhas órfãs
  • você pode obter o comportamento "em cascata de exclusão", limpando tabelas automaticamente
  • saber sobre os relacionamentos entre as tabelas no banco de dados ajuda o Otimizador a planejar suas consultas para uma execução mais eficiente, pois é capaz de obter melhores estimativas na junção de cardinalidade.
  • Os FKs dão uma grande dica sobre quais estatísticas são mais importantes para coletar no banco de dados, o que, por sua vez, leva a um melhor desempenho
  • eles permitem todos os tipos de suporte gerado automaticamente - os ORMs podem gerar eles mesmos, as ferramentas de visualização poderão criar layouts de esquemas agradáveis ​​para você, etc.
  • alguém novo no projeto entrará no fluxo das coisas mais rápido, já que os relacionamentos implícitos são explicitamente documentados

Razões para não usar chaves estrangeiras:

  • você está fazendo o DB trabalhar extra em toda operação CRUD porque ele tem que verificar a consistência do FK. Isso pode ser um grande custo se você tiver muita rotatividade
  • ao impor relacionamentos, os FKs especificam uma ordem na qual você precisa adicionar/excluir coisas, o que pode levar à recusa do DB em fazer o que você quer. (Concedido, em tais casos, o que você está tentando fazer é criar um Orphaned Row, e isso geralmente não é uma coisa boa). Isso é especialmente doloroso quando você está fazendo grandes atualizações em lote, e você carrega uma tabela antes da outra, com a segunda tabela criando um estado consistente (mas você deveria estar fazendo esse tipo de coisa se houver a possibilidade de o segundo carregamento falhar e seu banco de dados é agora inconsistente?).
  • às vezes você sabe de antemão que seus dados estarão sujos, você aceita isso e quer que o DB os aceite.
  • você está apenas sendo preguiçoso :-)

Eu acho (não estou certo!) Que os bancos de dados mais estabelecidos fornecem uma maneira de especificar uma chave estrangeira que não é aplicada, e é simplesmente um pouco de metadados. Como a não aplicação elimina todas as razões para não usar FKs, você provavelmente deve seguir esse caminho se qualquer um dos motivos da segunda seção se aplicar.

341
SquareCog

Esta é uma questão de educação. Se em algum lugar de sua carreira educacional ou profissional você passou o tempo alimentando e cuidando de bancos de dados (ou trabalhou de perto com pessoas talentosas que o fizeram), então os princípios fundamentais de entidades e relacionamentos estão bem arraigados em seu processo de pensamento. Entre esses rudimentos está como/quando/por que especificar chaves em seu banco de dados (primário, externo e talvez alternativo). É uma segunda natureza.

Se, no entanto, você não teve uma experiência tão completa ou positiva em seu passado com esforços relacionados ao RDBMS, provavelmente não foi exposto a essas informações. Ou talvez o seu passado inclua imersão em um ambiente que era vociferantemente anti-banco de dados (por exemplo, "esses DBAs são idiotas - nós, poucos, escolhemos poucos slingers com código Java/c # salvarão o dia"), caso em que você pode se opor veementemente para os balbucios arcanos de algum dweeb te dizendo que os FKs (e as restrições que eles podem implicar) são realmente importantes se você apenas ouvisse.

A maioria das pessoas foi ensinada quando eram crianças que escovar os dentes era importante. Você pode passar sem isso? Claro, mas em algum lugar abaixo da linha você terá menos dentes disponíveis do que você poderia ter se você tivesse escovado após cada refeição. Se as mães e os pais fossem responsáveis ​​o suficiente para cobrir o design do banco de dados, bem como a higiene oral, não teríamos essa conversa. :-)

78
Ed Lucas

Tenho certeza de que há muitos aplicativos nos quais você pode se dar bem, mas não é a melhor ideia. Você não pode sempre contar com seu aplicativo para gerenciar adequadamente seu banco de dados e, francamente, o gerenciamento do banco de dados não deve ser motivo de grande preocupação para o seu aplicativo.

Se você estiver usando um banco de dados relacional, então parece que você deve ter alguns relacionamentos definidos nele. Infelizmente, essa atitude (você não precisa de chaves estrangeiras) parece ser adotada por muitos desenvolvedores de aplicativos que preferem não se incomodar com coisas bobas como integridade de dados (mas precisam porque suas empresas não têm desenvolvedores de banco de dados dedicados). Normalmente, em bancos de dados reunidos por esses tipos, você tem sorte de ter apenas chaves primárias;)

52
AlexCuse

Chaves estrangeiras são essenciais para qualquer modelo de banco de dados relacional.

39
Galwegian

Eu sempre os uso, mas depois faço bancos de dados para sistemas financeiros. O banco de dados é a parte crítica do aplicativo. Se os dados em um banco de dados financeiro não forem totalmente precisos, não importa quanto esforço você dedique ao design de código/front-end. Você está apenas perdendo seu tempo.

Há também o fato de que múltiplos sistemas geralmente precisam interagir diretamente com o banco de dados - de outros sistemas que simplesmente lêem dados (Crystal Reports) para sistemas que inserem dados (não necessariamente usando uma API que eu criei; pode ser escrito por um Um gerente obtuso que acabou de descobrir o VBScript e tem a senha SA para a caixa SQL. Se o banco de dados não for tão idiotas quanto possível, banco de dados do bye bye.

Se seus dados são importantes, então sim, use chaves estrangeiras, crie um conjunto de procedimentos armazenados para interagir com os dados e faça o DB mais difícil possível. Se os seus dados não são importantes, por que você está criando um banco de dados para começar?

29
Ant

Update : Eu sempre uso chaves estrangeiras agora. Minha resposta à objeção "eles complicaram o teste" é "escrever seus testes de unidade para que eles não precisem do banco de dados. Quaisquer testes que usem o banco de dados devem usá-lo corretamente, e isso inclui chaves estrangeiras. Se a configuração for dolorosa, encontrar uma maneira menos dolorosa de fazer a configuração ".


Chaves estrangeiras complicam o teste automatizado

Suponha que você esteja usando chaves estrangeiras. Você está escrevendo um teste automatizado que diz "quando eu atualizar uma conta financeira, ele deve salvar um registro da transação". Neste teste, você está preocupado apenas com duas tabelas: accounts e transactions.

No entanto, accounts tem uma chave estrangeira para contracts e contracts tem um fk para clients e clients tem um fk para cities e cities tem um fk para states.

Agora, o banco de dados não permitirá que você execute seu teste sem configurar dados em quatro tabelas que não estejam relacionadas ao seu teste .

Existem pelo menos duas perspectivas possíveis sobre isso:

  • "Isso é uma coisa boa: seu teste deve ser realista, e essas restrições de dados existirão em produção."
  • "Isso é uma coisa ruim: você deve ser capaz de unir peças de teste do sistema sem envolver outras peças. Você pode adicionar testes de integração para o sistema como um todo."

Também pode ser possível desativar temporariamente as verificações de chave estrangeira durante a execução de testes. MySQL, pelo menos, suporta isso .

18
Nathan Long

"Eles podem tornar a exclusão de registros mais complicada - você não pode excluir o registro" principal "onde há registros em outras tabelas em que chaves estrangeiras violam essa restrição."

É importante lembrar que o padrão SQL define ações que são tomadas quando uma chave estrangeira é excluída ou atualizada. Os que eu conheço são:

  • ON DELETE RESTRICT - Impede que quaisquer linhas na outra tabela que tenham chaves nesta coluna sejam excluídas. Isso é o que Ken Ray descreveu acima.
  • ON DELETE CASCADE - Se uma linha da outra tabela for excluída, exclua as linhas dessa tabela que a referenciem.
  • ON DELETE SET DEFAULT - Se uma linha na outra tabela for excluída, defina quaisquer chaves estrangeiras referenciando-as ao padrão da coluna.
  • ON DELETE SET NULL - Se uma linha na outra tabela for excluída, defina quaisquer chaves estrangeiras referenciando-as nesta tabela como nulas.
  • ON DELETE NO ACTION - Esta chave estrangeira apenas marca que é uma chave estrangeira; ou seja, para uso em mapeadores OR.

Essas mesmas ações também se aplicam a ON UPDATE.

O padrão parece depender do servidor sql que você está usando.

14
Powerlord

@imphasing - este é exatamente o tipo de mentalidade que causa pesadelos de manutenção.

Por que, oh, por que você ignora a integridade referencial declarativa, em que os dados podem ser garantidos como pelo menos consistentes, em favor da chamada "aplicação de software", que é uma medida preventiva fraca na melhor das hipóteses.

14
Ed Guiness

Há uma boa razão para não usá-los: Se você não entende o papel deles ou como usá-los.

Nas situações erradas, as restrições de chave estrangeira podem levar à replicação em cascata de acidentes. Se alguém remover o registro errado, desfazer isso pode se tornar uma tarefa gigantesca.

Além disso, ao contrário, quando você precisar remover algo, se as restrições forem mal projetadas, poderão causar todos os tipos de bloqueios que o impedem.

12
Kent Fredric

Não existem boas razões não para usá-las ... a menos que linhas órfãs não sejam grandes lidar com você, eu acho.

11
Matt Rogish

A grande questão é: você dirigiria com uma venda nos olhos? É assim que você desenvolve um sistema sem restrições de referência. Lembre-se de que os requisitos de negócios mudam, as alterações no design do aplicativo, as respectivas suposições lógicas nas alterações de código, a própria lógica pode ser refatorada e assim por diante. Em geral, restrições em bancos de dados são postas em prática sob suposições lógicas contemporâneas, aparentemente corretas para um conjunto particular de asserções e suposições lógicas.

Por meio do ciclo de vida de um aplicativo, as restrições de referência e verificação de dados policiam a coleta de dados por meio do aplicativo, especialmente quando novos requisitos geram alterações no aplicativo lógico.

Para o assunto desta listagem - uma chave estrangeira por si só não "melhora o desempenho", nem "degradar o desempenho" significativamente do ponto de vista do sistema de processamento de transações em tempo real. No entanto, existe um custo agregado para verificação de restrição no sistema "batch" de volume HIGH. Então, aqui está a diferença, processo de transação em tempo real versus lote; Processamento em lote - quando o custo agregado, determinado por verificações de restrição, de um lote processado seqüencialmente, causa um impacto no desempenho.

Em um sistema bem projetado, as verificações de consistência de dados seriam feitas "antes" do processamento de um lote (embora, também, haja um custo associado aqui); portanto, as verificações de restrição de chave estrangeira não são necessárias durante o tempo de carregamento. Na verdade, todas as restrições, incluindo a chave estrangeira, devem ser temporariamente desativadas até que o lote seja processado.

QUERY PERFORMANCE - se as tabelas forem unidas em chaves estrangeiras, esteja ciente do fato de que colunas de chave estrangeira NÃO ESTÃO INDEXADAS (embora a respectiva chave primária seja indexada por definição). Ao indexar uma chave estrangeira, nesse caso, indexando qualquer chave, e juntando tabelas em indexadas ajuda com melhores desempenhos, não unindo-se a chave não indexada com restrição de chave estrangeira nela.

Mudando de assunto, se um banco de dados está apenas suportando conteúdo de exibição/renderização de sites/etc e cliques de gravação, então um banco de dados com restrições completas em todas as tabelas é sobre kill para tais propósitos. Pense nisso. A maioria dos sites nem usa um banco de dados para isso. Para requisitos semelhantes, onde os dados estão apenas sendo gravados e não referenciados por palavra, use um banco de dados na memória, que não possui restrições. Isso não significa que não há modelo de dados, sim modelo lógico, mas nenhum modelo de dados físico.

5
jasbir L

Da minha experiência, é sempre melhor evitar o uso de FKs em Aplicativos Críticos de Banco de Dados. Eu não discordaria dos caras que dizem que o FKs é uma boa prática, mas não é prático onde o banco de dados é enorme e tem operações CRUD enormes/s. Eu posso compartilhar sem nomear ... um dos maiores bancos de investimento não tem um único FK em bancos de dados. Essas restrições são tratadas pelos programadores durante a criação de aplicativos envolvendo o banco de dados. A razão básica é que sempre que um novo CRUD é feito, ele tem que efetuar várias tabelas e verificar cada inserção/atualização, embora isso não seja um grande problema para as consultas que afetam linhas únicas, mas cria uma enorme latência quando você lida com processamento em lote que qualquer grande banco tem que fazer como tarefas diárias.

É melhor evitar FKs, mas seu risco tem que ser tratado por programadores.

3
Rachit

"Antes de adicionar um registro, verifique se existe um registro correspondente em outra tabela" é lógica de negócios.

Aqui estão alguns motivos pelos quais você não deseja isso no banco de dados:

  1. Se as regras de negócios mudarem, você precisará alterar o banco de dados. O banco de dados precisará recriar o índice em muitos casos e isso é lento em tabelas grandes. (As regras de mudança incluem: permitir que os convidados postem mensagens ou permitam que os usuários excluam suas contas apesar de terem postado comentários, etc.).

  2. Alterar o banco de dados não é tão fácil quanto implementar uma correção de software, enviando as alterações para o repositório de produção. Queremos evitar alterar a estrutura do banco de dados tanto quanto possível. Quanto mais lógica de negócios houver no banco de dados, mais você aumentará as chances de precisar alterar os bancos de dados (e disparar a re-indexação).

  3. TDD. Em testes de unidade, você pode substituir o banco de dados por mocks e testar a funcionalidade. Se você tiver alguma lógica de negócios em seu banco de dados, não estará fazendo testes completos e precisaria testar com o banco de dados ou replicar a lógica de negócios no código para fins de teste, duplicando a lógica e aumentando a probabilidade da lógica não funcionar no banco de dados. mesmo caminho.

  4. Reutilizando sua lógica com diferentes fontes de dados. Se não houver lógica no banco de dados, meu aplicativo poderá criar objetos a partir de registros do banco de dados, criá-los a partir de um serviço da Web, um arquivo json ou qualquer outra origem. Eu só preciso trocar a implementação do mapeador de dados e usar toda a minha lógica de negócios com qualquer fonte. Se houver lógica no banco de dados, isso não é possível e você terá que implementar a lógica na camada do mapeador de dados ou na lógica de negócios. De qualquer forma, você precisa desses cheques no seu código. Se não houver lógica no banco de dados, posso implantar o aplicativo em locais diferentes usando diferentes implementações de banco de dados ou de arquivo simples.

3
Tom B

Motivo Adicional para usar Chaves Estrangeiras: - Permite maior reutilização de um banco de dados

Motivo adicional para NÃO usar chaves estrangeiras: - Você está tentando prender um cliente em sua ferramenta reduzindo a reutilização.

3
Dan

Concordo com as respostas anteriores, pois elas são úteis para manter a consistência dos dados. No entanto, houve um post interessante por Jeff Atwood algumas semanas atrás, que discutiu os prós e contras de dados normalizados e consistentes.

Em poucas palavras, um banco de dados desnormalizado pode ser mais rápido ao lidar com grandes quantidades de dados; e você pode não se importar com a consistência precisa dependendo do aplicativo, mas obriga a ter muito mais cuidado ao lidar com dados, já que o DB não será.

2
Santiago Palladino

Conheço apenas bancos de dados Oracle, nenhum outro, e posso dizer que Chaves Estrangeiras são essenciais para manter a integridade dos dados. Antes de inserir dados, é necessário criar uma estrutura de dados e torná-la correta. Quando isso é feito - e, portanto, todas as chaves primárias e estrangeiras são criadas - o trabalho está feito!

Significado: linhas órfãs? Não. Nunca vi isso na minha vida. A menos que um mau programador tenha esquecido a chave estrangeira, ou se ele implementou isso em outro nível. Ambos são - no contexto da Oracle - erros enormes, que levarão à duplicação de dados, dados órfãos e, portanto: corrupção de dados. Não consigo imaginar um banco de dados sem o FK aplicado. Parece caos para mim. É um pouco como o sistema de permissões do Unix: imagine que todo mundo é root. Pense no caos.

Chaves estrangeiras são essenciais, assim como as chaves primárias. É como dizer: e se removêssemos as chaves primárias? Bem, o caos total vai acontecer. Isso é o que. Você não pode mover a responsabilidade da chave primária ou estrangeira para o nível de programação, ela deve estar no nível de dados.

Desvantagens? Sim absolutamente ! Porque na inserção, muito mais cheques vão estar acontecendo. Mas, se a integridade dos dados é mais importante que o desempenho, é um acéfalo. O problema com o desempenho no Oracle está mais relacionado aos índices, que vêm com o PK e o FK.

2
tvCa

Eles podem tornar a exclusão de registros mais complicada - você não pode excluir o registro "mestre" onde há registros em outras tabelas em que chaves estrangeiras violariam essa restrição. Você pode usar gatilhos para ter exclusões em cascata.

Se você escolheu a sua chave primária imprudentemente, então mudar esse valor se torna ainda mais complexo. Por exemplo, se eu tiver o PK da minha tabela de "clientes" como o nome da pessoa, e fizer dessa chave um FK na tabela "pedidos", se o cliente quiser alterar seu nome, então é uma dor real. Mas isso é apenas design de banco de dados de má qualidade.

Acredito que as vantagens em usar chaves de ignição superam quaisquer supostas desvantagens.

1
Ken Ray

Eu tenho que segunda a maioria dos comentários aqui, chaves estrangeiras são itens necessários para garantir que você tenha dados com integridade. As diferentes opções de ON DELETE e ON UPDATE permitirão que você contorne algumas das "quedas descidas" que as pessoas mencionam aqui em relação ao seu uso.

Acho que em 99% de todos os meus projetos terei FKs para impor a integridade dos dados, no entanto, há aquelas raras ocasiões em que tenho clientes que DEVEM manter seus dados antigos, independentemente de quão ruim seja .... mas depois passo muito tempo escrevendo códigos que entram apenas para obter os dados válidos de qualquer maneira, então fica sem sentido.

1
Mitchel Sellers

O argumento que ouvi é que o front-end deve ter essas regras de negócios. Chaves estrangeiras "adicionam sobrecarga desnecessária" quando você não deveria permitir inserções que quebrassem suas restrições. Eu concordo com isso? Não, mas é isso que sempre ouvi.

EDIT: Meu palpite é que ele estava se referindo a restrições de chave estrangeira , e não chaves estrangeiras como um conceito.

1
lordscarlet

Verificar as restrições de chave estrangeira leva algum tempo de CPU, então algumas pessoas omitem chaves estrangeiras para obter algum desempenho extra.

1
remonedo

O banco de dados Clarify é um exemplo de um banco de dados comercial que não possui chaves primárias ou estrangeiras.

http://www.geekinterview.com/question_details/18869

O engraçado é que a documentação técnica faz um grande esforço para explicar como as tabelas estão relacionadas, que colunas usar para se juntar a elas etc.

Em outras palavras, eles poderiam ter se juntado às tabelas com declarações explícitas (DRI), mas eles optaram por não .

Consequentemente, o banco de dados Clarify está cheio de inconsistências e apresenta um desempenho inferior.

Mas suponho que facilitou o trabalho dos desenvolvedores, não tendo que escrever código para lidar com a integridade referencial, como a verificação de linhas relacionadas antes de excluir, adicionar.

E isso, eu acho, é o principal benefício de não ter restrições de chave estrangeira em um banco de dados relacional. Isso torna mais fácil o desenvolvimento, pelo menos do ponto de vista do diabo e do cuidado.

1
Ed Guiness

Se você tiver absoluta certeza de que o sistema de banco de dados subjacente não será alterado no futuro, usarei chaves estrangeiras para garantir a integridade dos dados.

Mas aqui está outro motivo muito bom na vida real para não usar chaves estrangeiras:

Você está desenvolvendo um produto, que deve suportar diferentes sistemas de banco de dados.

Se você estiver trabalhando com o Entity Framework, que é capaz de se conectar a muitos sistemas de banco de dados diferentes, talvez também queira oferecer suporte a bancos de dados sem servidor "de código aberto e gratuito". Nem todos esses bancos de dados podem suportar suas regras de chave estrangeira (atualização, exclusão de linhas ...).

Isso pode levar a problemas diferentes:

1.) Você pode encontrar erros quando a estrutura do banco de dados é criada ou atualizada. Talvez haja apenas erros silenciosos, porque suas chaves estrangeiras são apenas ignoradas pelo sistema de banco de dados.

2.) Se você confiar em chaves estrangeiras, provavelmente fará menos ou mesmo nenhuma verificação de integridade de dados em sua lógica de negócios. Agora, se o novo sistema de banco de dados não suportar essas regras de chave estrangeira ou apenas se comportar de uma maneira diferente, você precisará reescrever sua lógica de negócios.

Você pode perguntar: Quem precisa de diferentes sistemas de banco de dados? Bem, nem todos podem pagar ou querem um SQL Server completo em sua máquina. Este é o software, que precisa ser mantido. Outros já investiram tempo e dinheiro em algum outro sistema de DB. O banco de dados sem servidor é excelente para clientes pequenos em apenas uma máquina.

Ninguém sabe como todos esses sistemas de banco de dados se comportam, mas sua lógica de negócios, com verificações de integridade, permanece sempre a mesma.

1
Michael

Eu faço a resposta de Dmitriy - muito bem colocada.

Para aqueles que estão preocupados com a sobrecarga de desempenho que os FKs geralmente trazem, há uma maneira (no Oracle) de obter a vantagem do otimizador de consulta da restrição FK sem a sobrecarga de custo da validação de restrição durante a inserção, exclusão ou atualização. Isso é para criar a restrição FK com os atributos RELY DISABLE NOVALIDATE. Isso significa que o otimizador de consulta ASSUME que a restrição foi imposta ao criar consultas, sem que o banco de dados realmente impusesse a restrição. Você tem que ter muito cuidado aqui para assumir a responsabilidade ao preencher uma tabela com uma restrição FK como essa para ter absoluta certeza de que você não tem dados em suas colunas FK que violam a restrição, como se você fizesse isso. poderia obter resultados não confiáveis ​​de consultas que envolvem a tabela em que esta restrição FK está ativada.

Eu costumo usar essa estratégia em algumas tabelas no meu esquema de data mart, mas não no meu esquema de teste integrado. Eu me certifico de que as tabelas das quais estou copiando dados já tenham a mesma restrição imposta, ou a rotina ETL impõe a restrição.

1
Mike McAllister

Também ouvi esse argumento - de pessoas que esqueceram de colocar um índice em suas chaves estrangeiras e depois reclamaram que certas operações eram lentas (porque a verificação de restrições podia tirar proveito de qualquer índice). Então, para resumir: Não há uma boa razão para não usar chaves estrangeiras. Todos os bancos de dados modernos suportam exclusões em cascata, portanto ...

1
Arno

Para mim, se você quiser usar os padrões ACID , é fundamental ter chaves estrangeiras para garantir a integridade referencial.

1
CodeRot

Muitas das pessoas que respondem aqui ficam muito presas à importância da integridade referencial implementada através de restrições referenciais. Trabalhar em grandes bancos de dados com integridade referencial simplesmente não funciona bem. O Oracle parece particularmente ruim em exclusões em cascata. Minha regra geral é que os aplicativos nunca devem atualizar o banco de dados diretamente e devem ser feitos por meio de um procedimento armazenado. Isso mantém a base de código dentro do banco de dados e significa que o banco de dados mantém sua integridade.

Onde muitos aplicativos podem estar acessando o banco de dados, problemas surgem devido a restrições de integridade referencial, mas isso se resume a um controle.

Há também um problema mais amplo: os desenvolvedores de aplicativos podem ter requisitos muito diferentes aos quais os desenvolvedores de bancos de dados podem não estar necessariamente familiarizados.

1
Zak

Eu também acho que chaves estrangeiras são uma necessidade na maioria dos bancos de dados. A única desvantagem (além do impacto no desempenho que vem com a consistência forçada) é que ter uma chave estrangeira permite que as pessoas escrevam código que pressupõe que exista uma chave estrangeira funcional. Isso nunca deve ser permitido.

Por exemplo, vi pessoas escreverem um código que insere na tabela referenciada e, em seguida, tenta inserções na tabela de referência sem verificar se a primeira inserção foi bem-sucedida. Se a chave estrangeira for removida posteriormente, isso resultará em um banco de dados inconsistente.

Você também não tem a opção de assumir um comportamento específico na atualização ou exclusão. Você ainda precisa escrever seu código para fazer o que quiser, independentemente de haver uma chave estrangeira presente. Se você supõe que as exclusões estão em cascata quando não estão, suas exclusões falharão. Se você assumir que as atualizações das colunas referenciadas são propagadas para as linhas de referência quando não estiverem, suas atualizações falharão. Para fins de escrever código, você pode não ter esses recursos.

Se esses recursos estiverem ativados, seu código os emulará de qualquer maneira e você perderá um pouco de desempenho.

Então, o resumo .... chaves estrangeiras são essenciais se você precisar de um banco de dados consistente. Chaves estrangeiras nunca devem ser consideradas presentes ou funcionais no código que você escreve.

1
Eric

Uma vez, quando um FK pode causar um problema, é quando você tem dados históricos que referenciam a chave (em uma tabela de consulta), embora você não queira mais a chave disponível.
Obviamente, a solução é projetar as coisas com mais antecedência, mas estou pensando em situações do mundo real onde você nem sempre tem o controle da solução completa.
Por exemplo: talvez você tenha uma tabela de consulta customer_type que liste diferentes tipos de clientes - digamos que você precise remover um determinado tipo de cliente, mas (devido a restrições de negócios) não é capaz de atualizar o software cliente , e ninguém ocultou essa situação ao desenvolver o software, o fato de ser uma chave estrangeira em outra tabela pode impedir que você remova a linha, mesmo sabendo que os dados históricos referenciados são irrelevantes.
Depois de ser queimado com isso algumas vezes você provavelmente se afasta da imposição de relacionamentos.
(Não estou dizendo que isso é bom - apenas dando uma razão pela qual você pode decidir evitar as restrições FKs e db em geral)

0
hamishmcn

Em um projeto em que trabalhei, muitas vezes havia relacionamentos implícitos, em vez de explícitos, para que várias tabelas pudessem ser unidas na mesma coluna.

Pegue a tabela a seguir

endereço

  • AddressId (PK)
  • EntityId
  • Tipo de entidade
  • Cidade
  • Estado
  • País
  • Etc ..

Os valores possíveis de EntityType podem ser Employee, Company, Customer e o EntityId refere-se à chave primarky de qualquer tabela em que você estava interessado.

Eu realmente não acho que esta é a melhor maneira de fazer as coisas, mas funcionou para este projeto.

0
Curtis

Como muitas coisas, é uma troca. É uma questão de onde você quer fazer o trabalho para verificar a integridade dos dados:

(1) usar uma chave estrangeira (um único ponto para configurar para uma tabela, recurso já está implementado, testado, comprovado para funcionar)

(2) deixar para os usuários do banco de dados (possíveis múltiplos usuários/aplicativos atualizando as mesmas tabelas significando mais pontos potenciais de falha e maior complexidade nos testes).

É mais eficiente para o banco de dados fazer (2), mais fácil de manter e menos risco com (1).

0
Jen A

Eu vou repetir o que Dmitriy disse, mas adicionando um ponto.

Eu trabalhei em um sistema de faturamento em lote que precisava inserir grandes conjuntos de linhas em mais de 30 tabelas. Não nos foi permitido fazer uma bomba de dados (Oracle), então tivemos que fazer inserções em massa. Essas tabelas tinham chaves estrangeiras, mas já tínhamos garantido que não estavam quebrando nenhum relacionamento.

Antes de inserir, desabilitamos as restrições de chave estrangeira para que o Oracle não demore a fazer as inserções. Depois que a inserção for bem-sucedida, reativaremos as restrições.

PS: Em um banco de dados grande com muitas chaves estrangeiras e dados de linha filho para um único registro, às vezes, as chaves estrangeiras podem ser ruins, e você pode querer impedir as exclusões em cascata. Para nós, no sistema de faturamento, levaria muito tempo e seria muito desgastante no banco de dados se fizéssemos exclusões em cascata, portanto, marcamos o registro como ruim com um campo na tabela principal do driver (pai).

0
typicalrunt

No DB2, se MQTs (Tabelas de Consulta Materializada) forem usadas, as restrições de chave estrangeira serão necessárias para o otimizador escolher o plano correto para qualquer consulta. Como eles contêm as informações de cardinalidade, o otimizador usa os metadados intensamente para usar uma MQT ou não.

0
Senthil

Um bom princípio do design da estrutura de dados é garantir que cada atributo de uma tabela ou objeto esteja sujeito a uma restrição bem compreendida. Isso é importante porque, se você ou seu programa puder contar com dados válidos no banco de dados, é menos provável que você tenha defeitos no programa causados ​​por dados incorretos. Você também gasta menos tempo escrevendo código para lidar com condições de erro, e é mais provável que você escreva um código de tratamento de erros na frente.

Em muitos casos, essas restrições podem ser definidas em tempo de compilação, caso em que você pode gravar um filtro para garantir que o atributo sempre fique dentro do intervalo ou a tentativa de salvar o atributo falhe.

No entanto, em muitos casos, essas restrições podem mudar em tempo de execução. Por exemplo, você pode ter uma tabela "carros" que tenha "cor" como um atributo que inicialmente assume os valores, por exemplo, de "vermelho", "verde" e "azul". É possível, durante a execução do programa, adicionar cores válidas àquela lista inicial, e novos "carros" adicionados podem assumir qualquer cor na lista atualizada de cores. Além disso, você geralmente deseja que esta lista atualizada de cores sobreviva à reinicialização do programa.

Para responder à sua pergunta, verifica-se que, se você tiver uma exigência de restrição de dados que pode mudar em tempo de execução, e essas alterações devem sobreviver a uma reinicialização do programa, chaves estrangeiras são a solução mais simples e concisa para o problema. O custo de desenvolvimento é a adição de uma tabela (por exemplo, "cores", uma restrição de chave estrangeira à tabela "carros" e um índice) e o custo de tempo de execução é a consulta extra da tabela para as cores atualizadas. para validar os dados, e esse custo em tempo de execução é geralmente mitigado pela indexação e pelo armazenamento em cache.

Se você não usar chaves estrangeiras para esses requisitos, deverá escrever o software para gerenciar a lista, procurar entradas válidas, salvá-las em disco, estruturar os dados de maneira eficiente se a lista for grande, garantir que quaisquer atualizações na lista não sejam corrompa o arquivo de lista, forneça acesso serial à lista caso haja vários leitores e/ou gravadores, e assim por diante. Ou seja, você precisa implementar muita funcionalidade do RDBMS.

0
Jay Godse

Eu sempre achei que era preguiçoso não usá-los. Eu fui ensinado que sempre deveria ser feito. Mas então, eu não ouvi a discussão de Joel. Ele pode ter tido um bom motivo, não sei.

0
Kilhoffer

Q uite frequentemente recebemos os erros com restrições FK Não é possível adicionar ou atualizar uma linha filha: uma restrição de chave estrangeira falha Suponha que há duas tabelas inventory_source e contract_lines, e nós estão se referindo inventory_source_id em contract_lines de inventory_source e suponha que queremos excluir o registro de inventory_source e o registro já está presente em contract_lines ou queremos excluir a coluna PK da tabela Base, obtemos erros para restrições de FK, podemos evitá-lo usando as etapas anotadas abaixo.

CREATE TABLE inventory_source (
inventory_source_id int(11) NOT NULL AUTO_INCREMENT,
display_name varchar(40) NOT NULL,
state_id int(11) NOT NULL,
PRIMARY KEY (inventory_source_id),
KEY state_id (state_id),
CONSTRAINT ba_inventory_source_state_fk FOREIGN KEY (state_id) REFERENCES   ba_state (state_id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE contract_lines(
contract_line_id int(11) NOT NULL AUTO_INCREMENT,
inventory_source_id int(11) NULL ,
PRIMARY KEY (contract_line_id),
UNIQUE KEY contract_line_id (contract_line_id),
KEY AI_contract_line_id (contract_line_id),
KEY contract_lines_inventory_source_fk (inventory_source_id),
CONSTRAINT contract_lines_inventory_source_fk FOREIGN KEY       (inventory_source_id) REFERENCES ba_inventory_source (inventory_source_id)
) ENGINE=InnoDB AUTO_INCREMENT=135 DEFAULT CHARSET=utf8 ;

Podemos superá-lo usando os seguintes passos:

  1. Excluir ou atualizar a linha do inventory_source excluirá ou atualizará automaticamente as linhas correspondentes na tabela contract_lines e isso é conhecido como exclusão ou atualização em cascata.
  2. Outra maneira de fazer isso é configurar a coluna i.e. inventory_source_id na tabela contract_lines para NULL, quando um registro correspondente a ela é excluído da tabela inventory_source.
  3. Podemos restringir a tabela pai para excluir ou atualizar em outras palavras, pode-se rejeitar a operação de exclusão ou atualização para a tabela inventory_source.
  4. A tentativa de excluir ou atualizar um valor de chave primária não poderá continuar se houver um valor de chave estrangeira relacionado na tabela referenciada.
0
Vikas Kukreti