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)?
Respostas:
Razões para usar chaves estrangeiras:
Razões para não usar chaves estrangeiras:
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.
fonte
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. :-)
fonte
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;)
fonte
Chaves estrangeiras são essenciais para qualquer modelo de banco de dados relacional.
fonte
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?
fonte
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:
accounts
etransactions
.No entanto,
accounts
tem uma chave estrangeira paracontracts
, econtracts
tem um fk paraclients
, eclients
tem um fk paracities
ecities
tem um fk parastates
.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:
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 .
fonte
"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 sql servidor que você está usando.
fonte
@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.
fonte
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.
fonte
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.
fonte
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.
fonte
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.
fonte
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.
fonte
"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:
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.).
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).
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.
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.
fonte
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á.
fonte
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.
fonte
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.
fonte
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.
fonte
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.
fonte
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 ...
fonte
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.
fonte
Para mim, se você deseja seguir os padrões ACID , é fundamental ter chaves estrangeiras para garantir a integridade referencial.
fonte
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.
fonte
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
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.
fonte
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.
fonte
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.
fonte
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.
fonte
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.
fonte
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_type
que 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.fonte