Na minha experiência, muitos dos projetos que li no passado não tinham definições de relacionamento no banco de dados, mas apenas no código-fonte. Então, eu estou querendo saber quais são as vantagens / desvantagens de definir relações entre tabelas no banco de dados e no código-fonte? E a questão mais ampla é sobre outros recursos avançados em bancos de dados modernos, como cascata, gatilhos, procedimentos ... Há alguns pontos em meus pensamentos:
No banco de dados:
Corrija os dados do design. Evite erros de aplicativo que podem causar dados inválidos.
Reduza o ida e volta da rede para o aplicativo ao inserir / atualizar dados, pois o aplicativo precisa fazer mais consultas para verificar a integridade dos dados.
No código fonte:
Mais flexível.
Melhor ao escalonar para vários bancos de dados, pois às vezes a relação pode ser entre bancos de dados.
Mais controle sobre a integridade dos dados. O banco de dados não precisa verificar toda vez que o aplicativo modifica os dados (a complexidade pode ser O (n) ou O (n log n) (?)). Em vez disso, é delegado ao aplicativo. E acho que lidar com a integridade dos dados no aplicativo levará a mensagens de erro mais detalhadas do que usar o banco de dados. Por exemplo: quando você cria um servidor de API, se definir as relações no banco de dados, e algo der errado (como a entidade referenciada não existe), você receberá uma Exceção SQL com uma mensagem. A maneira mais simples será retornar 500 ao cliente, indicando que há um "erro interno do servidor" e o cliente não terá idéia do que está acontecendo de errado. Ou o servidor pode analisar a mensagem para descobrir o que está errado, o que é uma maneira feia e propensa a erros na minha opinião. Se você deixar o aplicativo lidar com isso,
Mais alguma coisa?
Edit: como Kilian aponta, meu argumento sobre desempenho e integridade de dados é muito equivocado. Então eu editei para corrigir o meu ponto lá. Entendo perfeitamente que deixar o banco de dados lidar com isso será uma abordagem mais eficiente e robusta. Por favor, verifique a pergunta atualizada e pense sobre isso.
Edit: obrigado a todos. As respostas que recebi apontam que as restrições / relações devem ser definidas no banco de dados. :). Tenho mais uma pergunta, pois ela está fora do escopo desta questão, acabei de postá-la como uma pergunta separada: Manipular erro de banco de dados no servidor API . Por favor, deixe algumas idéias.
fonte
Respostas:
TL; DR: As restrições de relacionamento devem estar no banco de dados.
Seu aplicativo não é grande o suficiente.
Você está correto, de fato, que a imposição de relacionamentos entre bancos de dados pode exigir a imposição deles no aplicativo.
Gostaria de salientar, no entanto, que você deve primeiro verificar a documentação do software de banco de dados que está usando e verificar as ofertas de produtos existentes. Por exemplo, existem ofertas de cluster sobre Postgres e MySQL.
E mesmo se você acabar precisando ter alguma validação na aplicação, não deitar fora o bebé com a água do banho . Afinal, quanto menos você precisar fazer, melhor estará.
Finalmente, se você estiver preocupado com problemas futuros de escalabilidade, receio que seu aplicativo precise sofrer alterações significativas antes que possa ser dimensionado de qualquer maneira. Como regra geral, toda vez que você cresce 10x, você precisa redesenhar ... então não vamos gastar muito dinheiro para não antecipar problemas de escalabilidade e, em vez disso, use dinheiro para realmente chegar ao ponto em que você tem esses problemas.
Seu aplicativo não está correto o suficiente.
Qual é a chance de o banco de dados usado ter uma implementação defeituosa da verificação em comparação com a chance de seu aplicativo ter uma implementação defeituosa da verificação?
E qual você altera com mais frequência?
Aposto que o banco de dados está correto a qualquer momento .
Seus desenvolvedores não estão pensando em distribuir o suficiente.
Bandeira vermelha ! 1 1
Se você está pensando:
você falhou no problema de concorrência mais básico: outro processo / thread pode estar adicionando o registro à medida que avança.
Se você está pensando:
você falhou em dar conta do MVCC: a visualização do banco de dados que você possui é uma captura instantânea no momento em que sua transação foi iniciada; ele não mostrar todas as atualizações que estão ocorrendo, e talvez nem mesmo cometeu.
Manter restrições em várias sessões é um problema muito difícil, seja feliz por ter sido resolvido no seu banco de dados.
1 A menos que seu banco de dados implemente corretamente a propriedade Serializable; mas poucos realmente o fazem.
Último:
Não analise mensagens de erro , se você usar qualquer banco de dados de nível de produção, ele retornará erros estruturados. Você terá algum código de erro, pelo menos, para indicar o que está possivelmente errado e, com base nesse código, poderá criar uma mensagem de erro adequada.
Observe que na maioria das vezes o código é suficiente: se você tiver um código de erro informando que não existe uma chave estrangeira referenciada, é provável que esta tabela tenha apenas uma chave estrangeira, para que você saiba no código qual é o problema .
Além disso, e sejamos honestos aqui, na maioria das vezes você não manipulará erros tão graciosamente de qualquer maneira. Só porque existem muitos deles e você deixará de dar conta de todos eles ...
... que apenas se vincula ao ponto de correção acima. Cada vez que você vê um "500: Erro interno do servidor" porque uma restrição de banco de dados foi acionada e não foi tratada, significa que o banco de dados salvou você, pois você esqueceu de lidar com isso no código.
fonte
Este é um ponto profundamente equivocado. Os bancos de dados foram criados precisamente para esse fim. Se você precisa de verificações de integridade de dados (e se acha que não precisa delas, provavelmente está enganado), deixar o banco de dados lidar com elas é quase certamente mais eficiente e menos propenso a erros do que fazê-lo na lógica do aplicativo.
fonte
As restrições devem estar no seu banco de dados, pois (com a melhor vontade do mundo), seu aplicativo não será a única coisa a acessar esse banco de dados.
Em algum momento, pode haver uma correção com script no banco de dados ou você pode precisar migrar dados de uma tabela para outra na implantação.
Além disso, você pode obter outros requisitos, como "O grande cliente X realmente precisa desta planilha de dados do Excel importada para o banco de dados de aplicativos esta tarde", onde você não terá o luxo de adaptar o código do aplicativo para se adequar a um script SQL sujo. em tempo.
É aqui que a integridade no nível do banco de dados salva seu bacon.
Além disso, imagine o desenvolvedor que assume sua função nesta empresa depois que você sai e é encarregado de fazer alterações no banco de dados.
Ele vai te odiar se não houver restrições de FK no banco de dados para que ele possa dizer quais relacionamentos uma tabela tem antes de alterá-la? ( Pista, a resposta é sim )
fonte
Você deve ter relações no banco de dados.
Como a outra resposta observa, o desempenho da verificação de restrições será muito melhor nesse banco de dados do que no aplicativo. As verificações de restrição de banco de dados são uma das coisas em que os bancos de dados são bons.
Se você precisar de flexibilidade adicional - por exemplo, suas referências cruzadas no banco de dados -, poderá remover as restrições deliberadamente e com consideração. Ter consistência em seu banco de dados significa que você tem a opção de modificar essas restrições e a certeza da integridade referencial.
fonte
Você pode realmente escrever e testar o código de imposição de integridade referencial quando tiver um código de resolução de problemas no domínio para escrever?
fonte
Se você não validar a integridade dos dados, restrições, relacionamentos etc. no nível do banco de dados, isso significa que é muito mais fácil para qualquer pessoa com acesso ao banco de dados de produção (através de qualquer outro cliente, incluindo uma ferramenta de acesso ao banco de dados) atrapalhar seus dados.
É uma boa prática impor a mais estrita integridade de dados possível no nível do banco de dados. Confie em mim, isso poupará enormes dores de cabeça ao longo do tempo em qualquer sistema não trivial. Você também detectará erros de lógica de aplicativo ou erros de requisitos de negócios e inconsistências mais rapidamente se uma reflexão cuidadosa for colocada nisso.
Como observação lateral, projete seu banco de dados da maneira mais normalizada e atômica possível. Não há mesas de "Deus". Gaste muito esforço projetando seu banco de dados para ser o mais simples possível, idealmente com muitas tabelas pequenas que são individualmente muito bem definidas, com uma única responsabilidade e cuidadosamente validadas em todas as colunas. O banco de dados é o último guardião da sua integridade dos dados. Representa a Fortaleza do Castelo.
fonte
A maioria das pessoas está dizendo essencialmente "sim, em geral você sempre definirá as relações no banco de dados". Mas se as disciplinas em ciência da computação fossem tão fáceis, seríamos chamados de "Leitores de manuais de software" em vez de "Engenheiros de software". Na verdade, eu concordo que as restrições devem estar no banco de dados, a menos que haja um bom motivo para não fazê-lo, então deixe-me fornecer alguns motivos que podem ser considerados bons em determinadas situações:
Código duplicado
Às vezes, existe uma certa quantidade de funcionalidade que pode ser manipulada pelo banco de dados no código do aplicativo. Se adicionar algo como restrições ao banco de dados for redundante, é melhor não duplicar a funcionalidade, porque você está violando os princípios DRY e pode piorar o ato de malabarismo de manter o banco de dados e o código do aplicativo sincronizados.
Esforço
Se o seu banco de dados já estiver fazendo o que é necessário sem o uso de recursos avançados, convém avaliar onde seu tempo, dinheiro e esforço devem ser colocados. Se a adição de restrições impediria uma falha catastrófica e, assim, poupar muito dinheiro à sua empresa, provavelmente vale a pena. Se você estiver adicionando restrições que devem manter, mas já garantem que nunca serão violadas, você estará perdendo tempo e poluindo sua base de códigos. Garantido é a palavra operativa aqui.
Eficiência
Normalmente, esse não é um bom motivo, mas em alguns casos você pode ter um determinado requisito de desempenho. Se o código do aplicativo puder implementar uma certa funcionalidade de maneira mais rápida que o banco de dados, e você precisar de desempenho extra, poderá ser necessário implementar o recurso no código do aplicativo.
Ao controle
Um pouco relacionado à eficiência. Às vezes, você precisa de um controle extremamente refinado sobre como um recurso é implementado e, às vezes, fazer com que o banco de dados o manipule oculte-o atrás de uma caixa preta que você precisa abrir.
Pontos finais
A última coisa que direi é que você saberá se não deve colocar a funcionalidade no banco de dados. Se você não tiver certeza, provavelmente será melhor usar os recursos do banco de dados, porque eles geralmente funcionam muito bem.
fonte
Como sempre, há muitas respostas. Para mim, encontrei uma regra simples (bem, isso só funciona para uma abordagem centrada no modelo). Normalmente, concentro-me apenas nas diferentes camadas de aplicativos.
Se o modelo consistir em várias entidades e houver dependências entre as entidades, a camada de persistência deve refletir essas dependências com suas possibilidades. Portanto, se você estiver usando um RDBMS, também deverá usar chaves estrangeiras. A razão é simples. Dessa forma, os dados são sempre válidos na estrutura.
Qualquer instância que esteja trabalhando nessa camada de persistência pode confiar nela. Suponho que você esteja encapsulando essa camada via interface (serviço). Então aqui está o ponto em que o design termina e o mundo real começa.
Analisando seus pontos, especialmente as referências entre bancos de dados . Nesse caso, sim, não deve haver uma referência implementada no próprio RDBMS, mas no serviço. Mas antes de seguir esse caminho, não seria melhor considerar isso já durante o design?
Significa, se eu já sei, que existem partes que precisam ser armazenadas em um banco de dados diferente, então eu posso colocá-las e defini-las como modelo separado. Direito?
Você também está apontando que implementar isso no código é mais flexível . Certo, mas não parece que você está lidando com um design incompleto? Pergunte a si mesmo, por que você precisa de mais flexibilidade?
O problema de desempenho, devido às verificações de integridade no banco de dados, não é real. O RDBMS pode verificar essas coisas muito mais rapidamente do que qualquer implementação sua. Por quê? Bem, você tem que lidar com a interrupção da mídia, o RDBMS não. E pode otimizar essas verificações usando suas estatísticas também
Então você vê, tudo volta ao design. Claro que você pode dizer agora, mas e se um requisito desconhecido estiver aparecendo, um divisor de águas? Sim, pode acontecer, mas essas mudanças devem ser projetadas e planejadas também. ; o)
fonte
Você tem respostas muito boas, mas mais alguns pontos
Integridade de dados é o que um banco de dados foi projetado para fazer
Fazer simultaneidade adequada como uma exclusão de FK no nível do aplicativo seria horrível
A experiência em integridade de dados é com um DBA
Ao nível do programa de inserir, atualização, atualização em massa, inserção em massa, volume excluir ...
Thin client, cliente de espessura, cliente móvel ....
A integridade dos dados não é a experiência de um programador - lotes de código e alguém duplicado vai mexer isso
Digamos que você seja hackeado - você está com problemas de qualquer maneira, mas um hacker pode causar muitos danos através de um pequeno orifício se não houver proteção de integridade no banco de dados
Pode ser necessário manipular dados diretamente via SQL ou TSQL.
Ninguém lembrará de todas as regras de dados
fonte
Sua pergunta não faz sentido: se você pode alterar o banco de dados, é código, se não pode alterar o banco de dados, terá que criar suas restrições em outro lugar.
Um banco de dados que você pode alterar possui tanto código quanto qualquer linha de ruby, javascript, c # ou ada.
A questão sobre onde colocar uma restrição em seu sistema deve se resumir à confiabilidade, custo e facilidade de desenvolvimento.
fonte
Há toneladas de boas respostas aqui. Acrescentarei que, se você tiver um aplicativo escrito no idioma Y, poderá criar um código semelhante a uma restrição de banco de dados em Y. E então alguém quiser acessar seu banco de dados usando o idioma Z, precisará escrever o mesmo código novamente. Deus o ajude se as implementações não forem exatamente as mesmas. Ou quando um usuário comercial experiente se conecta ao seu banco de dados usando o Microsoft Access.
Minha experiência me diz que quando as pessoas não querem usar restrições de banco de dados, é porque estão realmente tentando fazer algo da maneira errada. Por exemplo, eles estão tentando carregar dados em massa e desejam deixar colunas não nulas por um tempo. Eles pretendem "consertar isso mais tarde" porque a situação que tornou crítica a restrição não nula "não pode acontecer neste caso". Outro exemplo pode ser quando eles estão tentando conectar dois tipos diferentes de dados na mesma tabela.
Pessoas mais experientes darão um passo atrás e encontrarão uma solução que não envolva a tentativa de contornar uma restrição. A solução poderia ser simplesmente a restrição não é mais adequada porque os negócios mudaram, é claro.
fonte