Devo definir as relações entre tabelas no banco de dados ou apenas no código?

60

Na minha experiência, muitos dos projetos que li no passado não tinham definições de relacionamento no banco de dados, em vez disso, eles apenas os definiam 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:

  • Corrigir dados do design. Evite erros de aplicativos que podem causar dados inválidos.

  • Reduza a viagem de 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 quando escalar 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 dados (a complexidade pode ser O (n) ou O (n log n) (?)). Em vez disso, ele é delegado para o 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 você 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 simples será retornar 500 para o cliente que há um "Erro interno do servidor" e o cliente não terá idéia do que está 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ê permitir que o aplicativo manipule isso, o servidor poderá gerar uma mensagem mais significativa para o cliente.

Existe mais alguma coisa?

Edit: como Kilian aponta, meu ponto sobre performance & a integridade dos dados é muito equivocada. Então eu editei para corrigir o meu ponto lá. Eu entendo totalmente que deixar o banco de dados lidar com isso será uma abordagem mais eficiente e robusta. Por favor, verifique a pergunta atualizada e pense um pouco sobre isso.

Edit: obrigado a todos. As respostas que recebi apontam que as restrições / relações devem ser definidas no banco de dados. :) Eu tenho mais uma pergunta, como é bastante fora do escopo desta questão, eu acabei de postar como uma questão separada: Tratar erro de banco de dados para o servidor de API . Por favor, deixe algumas idéias.

    
por Yoshi 26.10.2016 / 08:47
fonte

11 respostas

70

TL; DR: Restrições de relacionamento devem estar no banco de dados.

Sua inscrição não é grande o suficiente.

Você está correto, de fato, que impor relacionamentos entre os bancos de dados pode exigir sua aplicação 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 clustering no topo do Postgres e MySQL.

E mesmo se você precisar ter alguma alguma validação no aplicativo, não jogue fora o bebê com a água do banho . Afinal, quanto menos você tem que fazer, melhor para você.

Por fim, se você estiver preocupado com problemas futuros de escalabilidade, receio que seu aplicativo tenha que passar por mudanças significativas antes que possa ser dimensionado de qualquer maneira. Como regra geral, cada vez que você cresce 10x, você tem que redesenhar ... então não vamos gastar muito dinheiro em deixar de antecipar os problemas de escalabilidade, e em vez disso usar o dinheiro para realmente chegar ao ponto em que você tem esses problemas.

Sua inscrição não está correta o suficiente.

Qual é a chance de que o banco de dados que você usa tenha uma implementação defeituosa da verificação em comparação à chance de que sua aplicação tenha uma implementação defeituosa da verificação?

E qual você altera com mais frequência?

Eu apostaria que o banco de dados está correto, a qualquer momento .

Seus desenvolvedores não estão achando distribuídos o suficiente.

Reduce network round trip to application when insert/update data as application has to make more query(s) to check data integrity.

Bandeira Vermelha ! 1

Se você está pensando:

  • verifique se o registro existe
  • se não, insira o registro

então você falhou o problema de simultaneidade mais básico: outro processo / thread pode estar adicionando o registro durante o processo.

Se você está pensando:

  • verifique se o registro existe
  • se não, insira o registro
  • verifique se o registro foi inserido como duplicado

você falhou para contabilizar o MVCC: a exibição do banco de dados que você tem é um instantâneo no momento em que sua transação foi iniciada; ele não mostra todas as atualizações que estão ocorrendo, e talvez nem esteja comprometido.

Manter restrições em várias sessões é um problema realmente difícil, fique feliz que tenha sido resolvido em seu banco de dados.

1 A menos que seu banco de dados implemente corretamente a propriedade Serializable; mas poucos realmente fazem.

Última:

And I think, handle data integrity in application will let to more verbose error message than using database. Eg: when you create an API server. If you define relations in database, and something go wrong(like the referenced entity doesn't exist), you will get an SQL Exception with message.

Não analise mensagens de erro , se você usar qualquer banco de dados de nível de produção, ele deve 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, você pode criar uma mensagem de erro adequada.

Note que na maioria das vezes o código é suficiente: se você tem um código de erro dizendo que uma chave estrangeira referenciada não existe, então é provável que esta tabela tenha apenas uma chave estrangeira, então você sabe no código o que o problema é.

Além disso, e vamos ser honestos aqui, na maioria das vezes você não vai lidar com erros que graciosamente de qualquer maneira. Só porque há muitos deles e você não conseguirá explicar todos eles ...

... que apenas se conecta ao ponto correção acima. Cada vez que você vê um "500: Internal Server Error" porque uma restrição de banco de dados disparou e não foi manipulada, isso significa que o banco de dados salvou você, já que você esqueceu de manipulá-lo no código.

    
por 26.10.2016 / 13:44
fonte
119

The database doesn't have to check for data integrity every time application modify data.

Este é um ponto profundamente equivocado. Bancos de dados foram criados precisamente para esse propósito. Se você precisar de verificações de integridade de dados (e se achar que não precisa delas, provavelmente estará 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. p>     

por 26.10.2016 / 08:53
fonte
51

As restrições devem estar dentro do seu banco de dados, pois (com a melhor do mundo), seu aplicativo não será a única coisa a acessar esse banco de dados.

Em algum momento, pode ser necessário corrigir um script no banco de dados ou talvez seja necessário migrar dados de uma tabela para outra na implantação.

Além disso, você pode obter outros requisitos, por exemplo "O grande cliente X realmente precisa desta folha de dados de excel importada para o nosso banco de dados de aplicativos esta tarde", onde você não terá o luxo de adaptar o código do seu aplicativo quando um script SQL sujo o fizer a tempo.

Aqui é onde a integridade no nível do banco de dados economizará seu bacon.

Além disso, imagine o desenvolvedor que assume sua função nesta empresa depois que você sai e, em seguida, é encarregado de fazer alterações no banco de dados.

Ele odiará você se não houver restrições de FK no banco de dados para que ele possa saber quais relacionamentos uma tabela possui antes de alterá-la? ( Clue, a resposta é sim )

    
por 26.10.2016 / 12:46
fonte
17

Você deve ter relações no banco de dados.

Como a outra resposta observa, o desempenho da verificação de restrição será muito melhor dentro desse banco de dados do que dentro de seu 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 de banco de dados cruzadas anotadas - então você pode 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.

    
por 26.10.2016 / 09:02
fonte
13
  • Nós não vivemos mais em um back-end < - > um mundo de front-end.
  • A maioria das soluções envolve um front-end da web, um front-end móvel, um front-end de lote e um front-end do iPad, etc.
  • Os mecanismos de banco de dados já possuem milhares de linhas de código testadas otimizadas para impor a integridade referencial.

Você pode realmente escrever e testar a integridade referencial impondo código quando você tem código de solução de problemas de domínio para escrever?

    
por 26.10.2016 / 15:27
fonte
2

Se você não validar sua integridade de 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 (por meio de qualquer outro cliente, incluindo uma ferramenta de acesso ao banco de dados) .

É uma ótima prática impor a integridade de dados mais rígida possível no nível do banco de dados. Confie em mim, isso vai 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 aplicativos ou erros de requisitos de negócios e inconsistências mais rapidamente, se pensar cuidadosamente nisso.

Como uma nota a esse respeito, projete seu banco de dados de uma maneira que seja o mais normalizada e atômica possível. Não há tabelas "Deus". Gastar 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 de sua integridade de dados. Representa a Fortaleza do Castelo.

    
por 26.10.2016 / 16:40
fonte
2

A maioria das pessoas está dizendo essencialmente "sim, em geral tu deves sempre define as relações no banco de dados". Mas se as disciplinas em ciência da computação fossem tão fáceis, nós seríamos chamados de "Leitores Manuais de Software" em vez de "Engenheiros de Software". Eu realmente concordo que as restrições devem estar no banco de dados, a menos que haja uma boa razão para que elas não devam , então deixe-me fornecer algumas razões que podem ser consideradas boas em certas situações:

Código duplicado

Às vezes, uma certa quantidade de funcionalidade que poderia ser manipulada pelo banco de dados existirá naturalmente no código do aplicativo. Se adicionar algo como restrições ao banco de dados seria redundante, seria melhor não duplicar a funcionalidade, porque você está violando os princípios do DRY e pode piorar o malabarismo de manter o banco de dados e o código do aplicativo em sincronia.

Esforço

Se o seu banco de dados já estiver fazendo o que precisa sem usar recursos avançados, convém avaliar onde seu tempo, dinheiro e esforço devem ser colocados. Se adicionar restrições impediria uma falha catastrófica e, portanto, economizaria muito dinheiro para sua empresa, provavelmente valeria a pena. Se você está adicionando restrições que devem ser mantidas, mas que já estão garantidas para nunca serem violadas, você está perdendo tempo e poluindo sua base de código. Garantido é a palavra-chave aqui.

Eficiência

Isso normalmente 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 determinada funcionalidade de maneira mais rápida que o banco de dados e você precisar de desempenho extra, talvez seja necessário implementar o recurso no código do aplicativo.

Controle

Algo relacionado à eficiência. Às vezes você precisa de um controle extremamente refinado sobre como um recurso é implementado e, às vezes, com o banco de dados manipulado, ele o oculta atrás de uma caixa preta que você precisa abrir.

Pontos de encerramento

  • Bancos de dados são escritos em código. Não há nada mágico que você não possa fazer no seu próprio código.
  • Nada é de graça. Restrições, relações, etc., todos usam ciclos de CPU.
  • As pessoas no mundo NoSQL se dão bem sem os recursos tradicionais do Relational. No MongoDB, por exemplo, a estrutura dos documentos JSON é boa o suficiente para suportar um banco de dados inteiro.
  • O uso cego e ignorante de recursos avançados de banco de dados não garante nenhum benefício. Você pode acidentalmente fazer algo funcionar apenas para quebrá-lo mais tarde.
  • Você fez uma pergunta muito geral sem listar requisitos ou restrições específicas. A verdadeira resposta à sua pergunta é "depende".
  • Você não especificou se esse era um problema de escala corporativa. Outras respostas estão falando sobre coisas como clientes e integridade de dados, mas às vezes essas coisas não são importantes.
  • Estou assumindo que você está falando sobre um banco de dados tradicional de SQL Relational.
  • Minha perspectiva vem de ter me afastado do uso de toneladas de restrições e chaves estrangeiras em projetos pequenos (até 50 tabelas), e não percebendo nenhuma desvantagem .

A última coisa que vou dizer é que você saberá se não deveria estar colocando a funcionalidade no banco de dados. Se você não tem certeza, provavelmente é melhor usar os recursos do banco de dados, porque eles geralmente funcionam muito bem.

    
por 27.10.2016 / 08:13
fonte
0

Como sempre, há muitas respostas. Para mim, encontrei uma regra simples (bem, só funciona para uma abordagem centrada no modelo). Normalmente, eu me concentro 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 deverá refletir essas dependências com suas possibilidades. Então, se você estiver usando um RDBMS, então você também deve usar chaves estrangeiras. 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. Estou assumindo que você está encapsulando essa camada via interface (serviço). Então aqui está o ponto onde o design termina e o mundo real começa.

Analisando seus pontos, especialmente 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 projeto?

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 um modelo separado. Certo?

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 feita por você. Por quê? Bem, você tem que lidar com a interrupção da mídia, o RDBMS não. E pode otimizar tais verificações usando suas estatísticas a.s.o.

Então você vê, tudo volta ao design. Claro que você pode dizer agora, mas e se um requisito desconhecido estiver aparecendo, um trocador de jogo? Sim, isso pode acontecer, mas tais mudanças devem ser planejadas e planejadas a.s.o ..; o)

    
por 26.10.2016 / 11:30
fonte
0

Você tem algumas respostas muito boas, mas mais alguns pontos

Integridade de dados é o que um banco de dados foi projetado para fazer

Fazer uma concorrência adequada como uma exclusão FK no nível do aplicativo seria horrível

A especialização em integridade de dados é com um DBA

No nível do programa, insira, atualize, atualize em massa, insira em massa, exclua em massa ...
Thin client, thick client, mobile client ...
A integridade dos dados não é o conhecimento de um programador - muitos códigos duplicados e alguém vai estragar tudo

Digamos que você seja hackeado - você está com problemas, mas um hacker pode causar muitos danos por meio de um pequeno buraco se não houver proteção de integridade no banco de dados

Você pode precisar manipular dados diretamente via SQL ou TSQL Ninguém vai se lembrar de todas as regras de dados

    
por 28.10.2016 / 16:23
fonte
0

Sua pergunta não faz sentido: se você pode alterar o banco de dados, é código, se você não pode alterar o banco de dados, você terá que criar suas restrições em outro lugar.

Um banco de dados que você pode alterar é tão codificado quanto qualquer linha de ruby, javascript, c # ou ada.

A questão sobre onde colocar uma restrição em seu sistema deve se resumir a confiabilidade, custo e facilidade de desenvolvimento.

    
por 28.10.2016 / 23:58
fonte
0

Há toneladas de boas respostas aqui. Acrescentarei que, se você tiver um aplicativo escrito na linguagem Y, poderá criar um código semelhante a uma restrição de banco de dados em Y. E, em seguida, alguém quiser acessar seu banco de dados usando o idioma Z, você precisará escrever o mesmo código novamente. Deus te ajude se as implementações não forem exatamente iguais. Ou quando um usuário de negócios 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 elas estão realmente tentando fazer algo da maneira errada. Por exemplo, eles estão tentando carregar dados em massa e querem deixar as colunas não-nulas nulas por um tempo. Eles pretendem "consertar isso depois" porque a situação que tornou a restrição não nula crítica "não pode acontecer neste caso". Outro exemplo pode ser quando eles tentam usar dois tipos diferentes de dados na mesma tabela.

Pessoas mais experientes darão um passo para trás e encontrarão uma solução que não envolva a tentativa de contornar uma restrição. A solução poderia simplesmente ser a restrição não é mais adequada porque o negócio mudou, é claro.

    
por 29.10.2016 / 19:28
fonte