O que há de errado com chaves estrangeiras?

259

Lembro-me de ouvir Joel Spolsky mencionar no podcast 014 que ele mal usava uma chave estrangeira (se bem me lembro). No entanto, para mim, eles parecem bastante vitais para evitar duplicação e problemas subsequentes de integridade de dados em todo o banco de dados.

As pessoas têm razões sólidas para explicar (para evitar uma discussão em consonância com os princípios do Stack Overflow)?

Edit: "Eu ainda tenho que ter um motivo para criar uma chave estrangeira, então esse pode ser o meu primeiro motivo para configurar uma."

Zolomon
fonte
9
Eu não acho que Joel não use FKs, é só que ele não faz o banco de dados aplicá-los. Logicamente, eles ainda são FKs!
Daren Thomas
6
Ele diz que não usa chaves estrangeiras, mas eu concordo com Daren que o que ele quer dizer é que ele não usa restrições estrangeiras. Uma coluna em uma tabela cujos valores devem ser obtidos da chave primária / exclusiva de outra tabela SÃO chaves estrangeiras, independentemente de você adicionar a restrição ou não.
23435 Tony Andrews
22
... Geralmente é tolice não adicionar a restrição: ele garante a integridade o tempo todo, mesmo se houver um erro no código do aplicativo ou se você estiver trabalhando nos bastidores fazendo uma "correção" de dados.
22310 Tony Tonys
2
+1 Para o comentário de Tony. Existe muita confusão entre o recurso e o conceito lógico de chaves estrangeiras por aí.
1940 JohnFx
4
@ DanMan, não sei onde você ganhou a impressão, eu acho isso. Na verdade, eu digo acima "Geralmente é tolice não acrescentar a restrição: ela garante a integridade o tempo todo"
Tony Andrews

Respostas:

352

Razões para usar chaves estrangeiras:

  • você não receberá linhas órfãs
  • você pode obter um bom comportamento "ao excluir cascata", limpando tabelas automaticamente
  • O conhecimento sobre os relacionamentos entre tabelas no banco de dados ajuda o Optimizer a planejar suas consultas para uma execução mais eficiente, pois é capaz de obter melhores estimativas sobre a cardinalidade da associação.
  • Os FKs dão uma dica bastante grande sobre quais estatísticas são mais importantes a serem coletadas 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 se gerar, as ferramentas de visualização poderão criar layouts de esquema agradáveis ​​para você etc.
  • alguém novo no projeto entrará no fluxo das coisas mais rapidamente, pois os relacionamentos implícitos são explicitamente documentados

Razões para não usar chaves estrangeiras:

  • você está fazendo o banco de dados funcionar extra em todas as operações CRUD porque ele precisa verificar a consistência do FK. Isso pode ser um grande custo se você tiver muita rotatividade
  • aplicando relacionamentos, os FKs especificam uma ordem na qual você deve adicionar / excluir itens, o que pode levar à recusa do banco de dados em fazer o que você deseja. (É verdade que, nesses casos, o que você está tentando fazer é criar uma Linha Órfã, e isso geralmente não é uma coisa boa). Isso é especialmente doloroso quando você está fazendo grandes atualizações em lote e carrega uma tabela antes da outra, com a segunda tabela criando um estado consistente (mas você deve fazer esse tipo de coisa se houver a possibilidade de a segunda carga falhar e o seu banco de dados agora é inconsistente?).
  • às vezes você sabe de antemão que seus dados ficarão sujos, você aceita isso e deseja que o banco de dados aceite
  • você está apenas sendo preguiçoso :-)

Eu acho (não tenho certeza!) Que a maioria dos bancos de dados estabelecidos fornece uma maneira de especificar uma chave estrangeira que não é imposta e é simplesmente um pouco de metadados. Como a não aplicação elimina todos os motivos para não usar FKs, você provavelmente deve seguir esse caminho se algum dos motivos da segunda seção se aplicar.

SquareCog
fonte
12
Boa lista! Os DBMs não verificarão a consistência para a parte "R" do CRUD, portanto, retirarei essa parte. Além disso, provavelmente é uma lavagem, porque no seu aplicativo você faz o mesmo que o DBMS: você verificará e garantirá que o ID pai seja válido antes do CRD e que seja realmente mais lento do que os DBMs o façam!
Matt Rogish 17/09/08
6
E se alguém excluir os pais enquanto você estiver inserindo filhos? Agora, quando envio "adicionar comentário" - se você já excluiu sua resposta, este comentário agora é órfão. FKs teriam evitado isso. Além disso, eu poderia mudar o parentID para o que eu quiser. Alguém precisa verificar. :)
Matt Rogish 17/09/08
7
Precisamente - deve ser o trabalho do DB, já que é o único que pode garantir a transacionalidade diante de vários clientes simultâneos.
SquareCog 17/09/08
3
+1 Excelente resposta - a segunda razão para não usar as restrições do FK pode ser pensada "dificulta a quebra da consistência", o que realmente parece uma coisa boa !
Bill Bill Karwin
9
Os benefícios de usar chaves estrangeiras FAR superam quaisquer benefícios de não usá-las na minha opinião.
Nick Bedford
80

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

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

Quando todos eram ensinados a quase todo mundo, era importante escovar os dentes. Você pode sobreviver sem ele? Claro, mas em algum ponto abaixo da linha você terá menos dentes disponíveis do que se tivesse escovado após cada refeição. Se mães e pais fossem responsáveis ​​o suficiente para cobrir o design do banco de dados e a higiene bucal, não teríamos essa conversa. :-)

Ed Lucas
fonte
61
Vou usar as destiladas "chaves estrangeiras são como escovar os dentes: vá em frente, fazer sem ele, mas cuidado quando você sorri"
Mark Sowul
5
Eu pessoalmente acho que os princípios de RDBMS' são muito mais simples e muito mais bem definida do que os de higiene oral
Ali Gangji
Em 10 anos no futuro, tenho certeza de que esse design de banco de dados falará com meu filho para que ele não estrague tudo e acabe sendo o motivo do próximo acidente de Wall Street por causa de um problema no banco de dados.
VarunAgw
52

Tenho certeza de que existem muitos aplicativos onde você pode se safar, mas essa não é a melhor ideia. Você nem sempre pode contar com seu aplicativo para gerenciar adequadamente seu banco de dados e o gerenciamento franco do banco de dados não deve ser muito preocupante para seu aplicativo.

Se você estiver usando um banco de dados relacional , 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 tolas como integridade de dados (mas precisam porque suas empresas não têm desenvolvedores de banco de dados dedicados). Normalmente, nos bancos de dados reunidos por esses tipos, você tem sorte apenas de ter chaves primárias;)

AlexCuse
fonte
26
Eu realmente não entendo pessoas que não têm FKs no banco de dados. A última vez que trabalhei com alguém que não tinha, ele disse "não, nós aplicamos isso no aplicativo". Exceto eu fiz um levantamento de todas as bases de dados de clientes e encontrou a maioria deles tinha órfãos ...
ErikE
1
Isso geralmente parece ser o caso. Eu acho que você poderia se safar da aplicação ONLY no banco de dados (desde que seus usuários não se importem com exceções de tempo de execução), mas ter as duas é realmente o único caminho a percorrer.
AlexCuse 13/09/10
Está tudo nas transcrições / na resposta de Atwood "Atwood: ... com base nas chaves estrangeiras que você define nos índices, eles descobrem ... Spolsky: [risos] Supondo que você faça isso. Atwood: Bem, assumindo que você configurou seu banco de dados corretamente ... "
MemeDeveloper 22/03
4
O banco de dados não é chamado de relacional por causa dos relacionamentos entre tabelas (TODOS os tipos de banco de dados têm algum tipo de relacionamento entre entidades!), Mas porque as próprias tabelas são relações , em termos matemáticos. Veja Wikipedia .
Massimiliano Kraus
41

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

galego
fonte
54
O modelo sim. A implementação, não essencial, provavelmente é útil.
dkretz
4
Desculpe, mas a principal razão pela qual os desenvolvedores de aplicativos não usam mais os sistemas de gerenciamento de banco de dados de objetos (também conhecidos como bancos de dados NoSQL!) É devido ao investimento em RDBMSs. Na maioria das vezes, o banco de dados (não o sistema de gerenciamento de banco de dados) é um modelo de objeto de camada intermediária, geralmente envolvendo caches distribuídos. É aqui que a exclusão em cascata, a propriedade e a sincronização das alterações devem ocorrer de qualquer maneira. O RDBMS é usado principalmente para a persistência desse modelo de objeto e, geralmente, após um exercício minucioso e praticamente inútil do ORM. Na maioria das vezes, os modelos de relação não são necessários!
Sentinel
2
não, chaves estrangeiras não são compulsary para indicar "relacional"
Silver Moon
Isso realmente não explica muito.
Nae
29

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, realmente não importa quanto esforço você dedique ao seu design de código / front-end. Você está apenas perdendo seu tempo.

Também existe o fato de que vários sistemas geralmente precisam interagir diretamente com o banco de dados - de outros sistemas que apenas lêem dados (Crystal Reports) a sistemas que inserem dados (não necessariamente usando uma API que eu projetei; pode ser gravado por um gerente estúpido que acabou de descobrir o VBScript e tem a senha do SA para a caixa SQL). Se o banco de dados não é tão à prova de idiotas quanto possível, adeus banco de dados.

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

Formiga
fonte
2
Bom insight. Eu argumentaria que os dados são importantes para todos os aplicativos que realmente são usados. A única coisa que difere são as consequências de dados corrompidos. Eles são elevados para o seu tipo de aplicação ...
Jay Godse
20

Atualização : Eu sempre uso chaves estrangeiras agora. Minha resposta para a objeção "eles complicaram o teste" é "escreva seus testes de unidade para que não precisem do banco de dados. Todos os testes que usam o banco de dados devem usá-lo adequadamente e incluem chaves estrangeiras. Se a instalação for dolorosa, encontre uma maneira menos dolorosa de fazer a configuração ".


Chaves estrangeiras complicam testes automatizados

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

No entanto, accountstem uma chave estrangeira para contracts, e contractstem um fk para clients, e clientstem um fk para citiese citiestem um fk para states.

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

Há pelo menos duas perspectivas possíveis sobre isso:

  • "Isso é bom: seu teste deve ser realista e essas restrições de dados existirão na produção".
  • "Isso é uma coisa ruim: você deve poder testar as peças 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. O MySQL, pelo menos, suporta isso .

Nathan Long
fonte
Eu me pego normalmente no caminho do meio aqui: uso FKs e escrevo métodos auxiliares de teste de unidade que configuram o banco de dados para suportar vários cenários de teste, por exemplo, um método auxiliar para preencher "cidades" e "estados" para quaisquer testes que precisam dessas tabelas preenchidas.
Joelpt
Talvez você deva ter usado tabelas de links entre entidades não relacionadas. Ou vá além - DBS separado: considere a situação em uma arquitetura orientada a serviços ou microsserviço, em que cada elemento (clientes, contas, transações) são sistemas diferentes, com bancos de dados diferentes. Não há FKs entre eles como todos. Nesse caso, os FKs devem ser usados ​​para evitar dados órfãos em subtabelas para cada tipo de dados.
precisa saber é o seguinte
3
Há também DBMS que permitem restrições para adiado para que eles só são verificados quando você comete toda a transação, assim que a ordem de inserção, atualização, exclusão não importa
a_horse_with_no_name
2
Se você estiver testando uma atualização de uma camada de negócios, seu ambiente de desenvolvimento deverá ter o FK presente. Ao atualizar seu registro, você deve ter os valores das colunas necessários para que a atualização seja bem-sucedida. Caso contrário, IMHO seu teste não é válido.
KeyOfJ
3
Seu banco de dados nem deveria estar envolvido nos testes de unidade, você deve zombar deles. No teste de integração, eles estariam envolvidos, mas qualquer problema devido a chaves estrangeiras é algo em que seus usuários também encontrarão, a menos que você o corrija.
Andreas Bergström
16

"Eles podem tornar a exclusão de registros mais complicados - você não pode excluir o registro" mestre "onde existem registros em outras tabelas em que chaves estrangeiras violariam essa restrição."

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

  • ON DELETE RESTRICT- Impede a exclusão de qualquer linha da outra tabela que possua chaves nesta coluna. Isto é o que Ken Ray descreveu acima.
  • ON DELETE CASCADE - Se uma linha na outra tabela for excluída, exclua todas as linhas nesta tabela que a referenciem.
  • ON DELETE SET DEFAULT - Se uma linha na outra tabela for excluída, defina quaisquer chaves estrangeiras que a referenciem ao padrão da coluna.
  • ON DELETE SET NULL - Se uma linha da outra tabela for excluída, defina quaisquer chaves estrangeiras que a referenciam nesta tabela como nulas.
  • ON DELETE NO ACTION- Essa chave estrangeira apenas marca que é uma chave estrangeira; especificamente para uso em mapeadores OR.

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

O padrão parece depender de qual servidor que você está usando.

Powerlord
fonte
14

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

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

Ed Guiness
fonte
Porque os desenvolvedores envolvidos nunca resolveram um problema que exige um modelo relacional não trivial, normalizado. Muitos problemas não, especialmente os que abundam na programação da web / "mídia social", que são toda a mania hoje. Se o que driblar o back-end de uma estrutura ORM satisfizer o problema em alfa, é improvável que alguém pense muito mais sobre modelagem de dados. Muitos desses problemas são tratados com a mesma facilidade pelas lojas K / V, bancos de dados de documentos ou serialização direta de objetos.
Zxq9 9/09/14
12

Há um bom motivo para não usá-los: se você não entende o papel deles ou como usá-los.

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

Por outro lado, quando você precisa remover algo, se mal projetado, as restrições podem causar todos os tipos de bloqueios que o impedem.

Kent Fredric
fonte
8
Excluir uma linha na produção sem backup não é um argumento válido. Se você não os entende, considere aprender sobre isso em vez de omiti-lo.
Guillaume
2
@ Guillaume Eu acho que a resposta dele foi um pouco sarcástica, e não deve ser tomada literalmente: se você não as entende, não as use. Mas é claro que você deve entender e usá-los.
22417 Benjamin Benjamin
^ Isso. São ferramentas úteis, mas nas mãos de um novato, são ferramentas perigosas.
21817 Kent Kentric
11

Não há boas razões para não usá-los ... a menos que linhas órfãs não sejam um grande problema para você, eu acho.

Matt Rogish
fonte
11
Por que as linhas órfãs são um grande negócio?
Seun Osewa
2
E o multithreading? Eles podem causar um pesadelo multithreading em determinadas situações. Em um aplicativo complexo com vários encadeamentos que escrevem o banco de dados que pode encontrar objetos que precisam se referir um ao outro, é melhor controlar a integridade referencial na lógica de negócios - especialmente se as tabelas ficarem estáticas posteriormente.
precisa saber é o seguinte
Concordo. Além disso, eu prefiro ter linhas ophan que eu possa recuperar mais tarde, do que tê-las descartadas sem piedade.
PedroD 21/09
4

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

Durante o ciclo de vida de um aplicativo, as verificações referenciais e de dados restringem a coleta de dados por meio do aplicativo, especialmente quando novos requisitos geram alterações lógicas no aplicativo.

Para o assunto desta listagem - uma chave estrangeira por si só "não melhora o desempenho", nem "prejudica o desempenho" significativamente do ponto de vista do sistema de processamento de transações em tempo real. No entanto, há um custo agregado para a verificação de restrições no sistema "lote" de alto volume. Então, aqui está a diferença, em tempo real versus processo de transação em lote; processamento em lote - onde um custo elevado, incorrido por verificações de restrição, de um lote processado sequencialmente representa um impacto no desempenho.

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

DESEMPENHO DA CONSULTA - se as tabelas forem unidas em chaves estrangeiras, esteja ciente do fato de que as colunas de chave estrangeira NÃO SÃO INDEXADAS (embora a respectiva chave primária seja indexada por definição). A indexação de uma chave estrangeira, nesse caso, a indexação de qualquer chave e a junção de tabelas em indexadas ajudam a obter melhores desempenhos, e não a junção de chaves não indexadas com restrição de chave estrangeira.

Mudando de assunto , se um banco de dados estiver apenas suportando a exibição do site / renderizando conteúdo / etc e registrando cliques, um banco de dados com restrições completas em todas as tabelas será eliminado para esse fim. Pense nisso. A maioria dos sites nem usa um banco de dados para tal. Para requisitos semelhantes, onde os dados estão sendo gravados e não referenciados, por exemplo, 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.

jasbir L
fonte
Bem, eu não sei por que inserir 3 novas linhas duplas no lugar de espaços em branco e mudar duas palavras conta como '67% é Jonathan Leffler ', mas não acho que tenha feito tanto trabalho nisso. O texto principal foi contribuído por @jay (usuário 183837).
31416 Jonathan Leffler
Apenas assumi que o paragrahps não funcionaria aqui, como é o caso na maioria dos outros sites. Então, eu coloquei tudo como um, usando negrito para alterar o fluxo.
Jasbir L
3

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 à sua ferramenta reduzindo a reutilização.

Dan
fonte
3

Pela minha experiência, é sempre melhor evitar o uso de FKs em aplicativos críticos de banco de dados. Eu não discordo dos caras aqui que dizem que os FKs são uma boa prática, mas não é prático onde o banco de dados é enorme e possui grandes operações CRUD / s. Eu posso compartilhar sem nomear ... um dos maiores bancos de investimento não possui um único FK nos bancos de dados. Essas restrições são tratadas pelos programadores ao criar aplicativos que envolvem DB. O motivo básico é que, sempre que um novo CRUD é feito, ele deve efetuar várias tabelas e verificar cada inserção / atualização, embora isso não seja um grande problema para consultas que afetam linhas únicas, mas cria uma latência enorme quando você lida com processamento em lote que qualquer grande banco precisa fazer como tarefas diárias.

É melhor evitar FKs, mas seu risco deve ser tratado pelos programadores.

Rachit
fonte
8
Não acho que as práticas de desenvolvimento em grandes bancos estabeleçam o padrão-ouro.
Adriaan Koster
3

"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 alteração incluem: permitir que os hóspedes publiquem mensagens ou permitir que os usuários excluam suas contas, apesar de terem publicado 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 o máximo possível. Quanto mais lógica de negócios houver no banco de dados, mais você aumentará as chances de precisar alterar os dados (e acionar a re-indexação).

  3. TDD. Nos testes de unidade, você pode substituir o banco de dados por zombarias e testar a funcionalidade. Se você possui alguma lógica de negócios em seu banco de dados, não está realizando 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 de a lógica não funcionar no mesma maneira.

  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 fonte. Eu só preciso trocar a implementação do mapeador de dados e posso usar toda a minha lógica de negócios com qualquer fonte. Se houver lógica no banco de dados, isso não será possível e você deverá implementar a lógica na camada do mapeador de dados ou na lógica de negócios. De qualquer forma, você precisa dessas verificações 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 arquivo simples.

Tom B
fonte
2

Concordo com as respostas anteriores, pois são úteis para manter a consistência dos dados. No entanto, houve um post interessante de Jeff Atwood, há algumas semanas, que discutia 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 você a ter muito mais cuidado ao lidar com dados, pois o banco de dados não será.

Santiago Palladino
fonte
Jeff faz alguns bons pontos. No entanto, Dan Chak no "Enterprise Rails" mostra uma maneira de projetar tabelas de cache que são essencialmente uma cópia desnormalizada dos dados. As consultas são rápidas e, se a tabela não precisar ser atualizada, ela funcionará bem. Descobri que, se seus dados direcionam o comportamento (por exemplo, estado do aplicativo), você precisa que os dados sejam normalizados o máximo possível, porque, caso contrário, dados inconsistentes levarão a um comportamento inconsistente do aplicativo.
Jay Godse
Um data warehouse desnormalizado pode ser útil ao ler grandes volumes de dados em caminhos de acesso previstos e consistentes . Em todos os outros cenários, essa é uma falácia perigosa.
Peter Wone
2

O banco de dados Clarify é um exemplo de 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 se esforça muito para explicar como as tabelas estão relacionadas, quais colunas usar para se juntar a elas etc.

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

Conseqüentemente, o banco de dados do Clarify está cheio de inconsistências e apresenta desempenho inferior.

Mas suponho que isso facilitou o trabalho dos desenvolvedores, sem a necessidade de escrever código para lidar com a integridade referencial, como verificar linhas relacionadas antes de excluir e adicionar.

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

Ed Guiness
fonte
O código para manipular uma verificação de integridade referencial com falha é muito menor que o código para manipular dados inconsistentes.
Jay Godse
@Jay concorda! Não pense que estou defendendo essa abordagem.
Ed Guiness
2

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, uma estrutura de dados precisa ser criada e corrigida. Quando isso é feito - e, portanto, todas as chaves primárias e estrangeiras são criadas - o trabalho é feito!

Significado: linhas órfãs? Não. Nunca vi isso na minha vida. A menos que um programador ruim esqueça a chave estrangeira, ou se ele a implementou em outro nível. Ambos são, no contexto da Oracle, grandes erros, 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 imposto. Parece um caos para mim. É um pouco como o sistema de permissão Unix: imagine que todo mundo é root. Pense no caos.

Chaves estrangeiras são essenciais, assim como Chaves primárias. É como dizer: e se removermos as Chaves Primárias? Bem, o caos total vai acontecer. Isso é o que. Você não pode mover a responsabilidade de 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 verificações vão acontecer. Mas, se a integridade dos dados é mais importante que o desempenho, é fácil. O problema com o desempenho no Oracle está mais relacionado aos índices, que vêm com PK e FK.

tvCa
fonte
1

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

Se você escolher sua chave primária imprudentemente, a alteração desse valor se tornará ainda mais complexa. Por exemplo, se eu tiver o PK da minha tabela de "clientes" como o nome da pessoa e tornar essa chave um FK na tabela "pedidos", se o cliente quiser alterar seu nome, será 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.

Ken Ray
fonte
5
Eu costumo excluir coisas de qualquer maneira. Basta marcar com um bit "Visível / ativo".
Dana
+1 para "Eu acredito que as vantagens do uso de chaves de ignição superam todas as supostas desvantagens"
Ian Boyd
2
Você nunca altera o valor de uma chave primária. Você exclui a linha inteira e a recria de maneira diferente. Se você acha que precisa alterá- lo, seu esquema está com defeito.
DanMan
Alterar o nome do cliente não seria um problema se a sua chave estrangeira estiver definida no CustomerId (PK). na tabela de pedidos. A única maneira de incomodar seria se o FK fosse definido no CustomerName, o que nunca deveria ser o caso. IMHO
KeyOfJ
1

A verificação das restrições de chave estrangeira leva algum tempo da CPU, portanto algumas pessoas omitem as chaves estrangeiras para obter um desempenho extra.

remonedo
fonte
6
Quanto tempo de CPU é gasto removendo dados duplicados e inconsistentes?
Ed Guiness
Sim, isso é verdade. Em um sistema em que trabalho, precisamos inserir 10 a 40 GB de dados por vez em um banco de dados e o desempenho do FK com e sem é visível no tempo total necessário.
Paul Mendoza
1

Também ouvi esse argumento - de pessoas que se 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 poderia tirar vantagem de qualquer índice). 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, então ...

Arno
fonte
9
Acredito que a verdadeira razão pela qual as restrições dos FKs não são usadas por alguns (a maioria, na minha perspectiva) é pura preguiça, sob o pretexto de que eles podem defender sua preguiça com seu argumento de economia de desempenho. Acredito firmemente que a grande maioria das Despesas de Estupidez em que nossa empresa incorre se deve à falta de aplicação de restrições de FK e ao efeito cascata que isso causa em uma empresa. A falta de chaves exclusivas é a outra coisa que me deixa louco ao lado de mais de 2000 procedimentos armazenados de linha com 12 níveis de IFs aninhados e recuo aleatório, mas vou parar agora.
Chad
1

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 quebrem suas restrições em primeiro lugar. Eu concordo com isso? Não, mas é isso que eu sempre ouvi.

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

lordscarlet
fonte
Não. Ele não gosta de chaves reais!
Ljs
Isso me surpreende. Há uma grande diferença entre não gostar de restrições de chave estrangeira e não gostar de chaves estrangeiras. Não tenho certeza de como você tem um banco de dados relacional sem eles.
lordscarlet 17/09/08
Sim, fiquei chocado quando o ouvi. Ele poderia ter sido involuntariamente irônico, no entanto; talvez ele vai postar aqui e esclarecer em algum momento :-)
LJS
1

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

CodeRot
fonte
1

Eu tenho que secundar 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 permitem que você contorne algumas das "quedas" mencionadas aqui em relação ao uso.

Acho que em 99% de todos os meus projetos terei FKs para reforçar a integridade dos dados, no entanto, existem aquelas raras ocasiões em que tenho clientes que DEVEM manter seus dados antigos, independentemente de quão ruim seja ... mas passo muito tempo escrevendo código que é usado para obter apenas os dados válidos de qualquer maneira, tornando-os inúteis.

Mitchel Sellers
fonte
1

Que tal manutenção e constância ao longo dos ciclos de vida do aplicativo? A maioria dos dados tem uma vida útil mais longa que os aplicativos que os utilizam. Os relacionamentos e a integridade dos dados são muito importantes para deixar a esperança de que a próxima equipe de desenvolvedores acerte no código do aplicativo. Se você não trabalhou em um banco de dados com dados sujos que não respeitam os relacionamentos naturais, você o fará. A importância da integridade dos dados ficará muito clara.


fonte
1

Eu também acho que chaves estrangeiras são uma necessidade na maioria dos bancos de dados. A única desvantagem (além da ocorrência de desempenho resultante da consistência imposta) é que ter uma chave estrangeira permite que as pessoas escrevam código que pressupõe que haja uma chave estrangeira funcional. Isso nunca deve ser permitido.

Por exemplo, eu vi pessoas escreverem código que é inserido na tabela referenciada e depois tenta inseri-lo 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 ao atualizar ou excluir. Você ainda precisa escrever seu código para fazer o que deseja, independentemente da presença de uma chave estrangeira. Se você assumir que as exclusões estão em cascata quando não estiverem, suas exclusões falharão. Se você presumir que as atualizações nas 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ê também 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.

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

Eric
fonte
1

Eu ecoo a resposta de Dmitriy - muito bem colocado.

Para aqueles que estão preocupados com a sobrecarga de desempenho que as FK costumam trazer, existe 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 imponha a restrição. Você precisa ter muito cuidado aqui para assumir a responsabilidade quando preencher uma tabela com uma restrição de FK como esta para garantir que você não tenha dados em suas colunas de FK que violam a restrição, como se você o fizesse. pode obter resultados não confiáveis ​​de consultas que envolvem a tabela em que esta restrição de FK está.

Normalmente, uso essa estratégia em algumas tabelas no meu esquema do data mart, mas não no meu esquema de temporariedade integrado. Certifico-me de que as tabelas das quais estou copiando dados já tenham a mesma restrição imposta ou a rotina ETL a imponha.

Mike McAllister
fonte
1

Muitas das pessoas que respondem aqui ficam muito preocupadas com a importância da integridade referencial implementada por meio 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 através 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 acessar o banco de dados, surgem problemas devido a restrições de integridade referenciais, mas isso depende de um controle.

Também existe um problema mais amplo: os desenvolvedores de aplicativos podem ter requisitos muito diferentes com os quais os desenvolvedores de banco de dados podem não estar familiarizados.

Zak
fonte
5
"os aplicativos nunca devem atualizar o banco de dados diretamente e devem ser feitos através 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." <- Há uma suposição aqui de que a lógica nos procedimentos armazenados não pode violar a integridade dos dados, o que é totalmente errado.
Tim Gautier
1

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

Mas aqui está outra boa razão da 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 pode se conectar a muitos sistemas diferentes de banco de dados, também poderá 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 diferentes problemas:

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 comercial. Agora, se o novo sistema de banco de dados não suportar essas regras de chave estrangeira ou se comportar de maneira diferente, será necessário reescrever sua lógica de negócios.

Você pode perguntar: Quem precisa de diferentes sistemas de banco de dados? Bem, nem todo mundo pode pagar ou deseja um SQL-Server completo em sua máquina. Este é um software que precisa ser mantido. Outros já investiram tempo e dinheiro em algum outro sistema de banco de dados. Os bancos de dados sem servidor são ótimos para pequenos clientes em apenas uma máquina.

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

Michael
fonte
0

Eu sempre pensei que era preguiçoso não usá-los. Foi-me ensinado que sempre deve ser feito. Mas então, eu não ouvi a discussão de Joel. Ele pode ter tido uma boa razão, eu não sei.

Kilhoffer
fonte
Foi mais uma observação imediata do que uma discussão, embora talvez eu deva pesquisar exatamente o que ele pensa sobre o assunto de forma independente! No entanto, eu estava curioso sobre a opinião da comunidade sobre esse tópico também!
Ljs
0

Uma vez em que um FK pode causar um problema é quando você tem dados históricos que referenciam a chave (em uma tabela de pesquisa), mesmo que você não queira mais a chave disponível.
Obviamente, a solução é projetar melhor as coisas antecipadamente, mas estou pensando em situações do mundo real aqui, onde você nem sempre tem o controle da solução completa. Depois de ser queimado com isso algumas vezes, você provavelmente se afasta da imposição de relações de banco de dados. (Não estou dizendo que isso seja bom - apenas fornecendo uma razão para que você decida evitar FKs e restrições de banco de dados em geral)
Por exemplo: talvez você tenha uma tabela de consulta customer_typeque lista tipos diferentes 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 do cliente e ninguém ocultou essa situação ao desenvolver o software, o fato de ser uma chave estrangeira em alguma outra tabela pode impedir a remoção da linha, mesmo que você conheça os dados históricos que o referenciam como irrelevantes.

hamishmcn
fonte
Se eu entendo o que você está tentando dizer, acho que minha resposta seria excluir logicamente o registro na tabela de pesquisa ou arquivar os dados históricos não mais relevantes e arquivar o registro de pesquisa também.
Chad