Digamos que eu tenha o seguinte diagrama de ER:
Agora, se eu representasse o relacionamento usando uma chave estrangeira de School
in Student
, eu poderia ter NULL
valores (porque a Student
não precisa pertencer a a School
), por exemplo:
Portanto, a maneira correta (com base no que li) é criar uma tabela de interseção para representar o relacionamento, por exemplo:
Dessa forma, nenhum NULL
valor pode estar presente na tabela School_has_Student
.
Mas quais são as desvantagens de usar uma chave estrangeira anulável em vez de criar uma tabela de interseção?
Editar:
Por engano, escolhi ( school_id
, student_id
) a chave primária da School_has_Student
tabela, o que tornava o relacionamento muitos para muitos. A chave primária correta deveria ter sido student_id
:
Respostas:
Os dois modelos representam relacionamentos diferentes.
Ao usar uma tabela de junção, você está modelando um relacionamento muitos para muitos.
Ao usar uma chave estrangeira simples, você está modelando um relacionamento um para muitos.
A desvantagem de uma chave estrangeira anulável é não poder modelar o relacionamento como muitos para muitos, se é isso que você está tentando realizar.
Com base na sua edição da pergunta, você efetivamente divide a tabela do aluno em duas tabelas com a mesma chave. Eu geralmente vejo isso em tabelas que têm campos demais, então alguém as divide em duas para serem mais gerenciáveis (eu chamo de batom em um porco).
Ao dividir a tabela do aluno, você está tornando a segunda tabela opcional porque um registro não precisa existir na segunda tabela. O que é muito semelhante a um campo que não precisa ser definido porque pode ser nulo.
Se você deseja um relacionamento um para muitos, é muito melhor usar uma única tabela e permitir que o ID da escola seja nulo na tabela do aluno. Não há motivo para evitar nulos nos campos, mesmo para uma chave estrangeira. Isso significa que o relacionamento externo é opcional: desenvolvedores e DBAs entendem isso claramente, e o mecanismo de banco de dados subjacente certamente deve funcionar bem.
Se você está preocupado com junções, não se preocupe. Existem semânticas bem definidas sobre como as junções funcionam com campos nulos. Usando uma única tabela, você pode unir duas tabelas em vez de três.
fonte
NULL
valores?student_id
uma chave primária naSchool_has_Student
tabela, que manteve o relacionamento como um para muitos. Quais são as desvantagens desse método ao usar uma chave estrangeira?Você escreveu em um comentário acima:
Quando houver muitos valores NULL na coluna de chave estrangeira, seus programas precisarão lidar com essa coluna quase sempre vazia para cada registro processado. A coluna provavelmente ocupará algum espaço em disco, embora em 98% de todos os casos esteja vazia, consultar o relacionamento significa consultar a coluna que oferece mais tráfego de rede e se você estiver usando um ORM que gera classes a partir de suas tabelas, programas também precisará de mais espaço no lado do cliente do que o necessário. O uso de uma tabela de interseção evita isso, haverá apenas registros de link necessários onde a chave estrangeira equivalente não seria NULL caso contrário.
Ao contrário, se você não possui apenas alguns valores NULL, digamos que 50% ou mais das relações não são NULL, o uso de uma tabela de interseção fornece o efeito oposto - mais espaço em disco, maior complexidade, resultando em mais tráfego na rede etc.
Portanto, o uso de uma tabela de interseção é apenas uma forma de otimização, sensível apenas a um caso específico e, especialmente nos dias de hoje, em que o espaço em disco e a memória se tornaram mais baratos, muito menos necessários. Observe que "Fundamentos de sistemas de banco de dados" foi originalmente escrito há mais de 20 anos (encontrei uma referência à segunda edição de 1994) e acho que essa recomendação já estava lá naquela época. Antes de 1994, a otimização do espaço era provavelmente muito mais importante do que hoje, pois o armazenamento em massa ainda era mais caro e os computadores e as redes eram muito mais lentos do que hoje.
Como uma observação lateral a um comentário exigente: a afirmação acima está apenas tentando antecipar o que o autor de "Fundamentos de sistemas de banco de dados" tinha em mente com sua recomendação, acho que ele estava fazendo uma afirmação geral grosseira, válida para a maioria dos sistemas. Em alguns bancos de dados, existem outras otimizações possíveis, como "colunas esparsas", que tornam o uso de uma tabela de interseção ainda mais obsoleto.
Portanto, não entenda mal essa recomendação. O livro não diz para você preferir tabelas de interseção para
{0,1}:n
relacionamentos em geral, ou - como você escreveu - que essa é a "maneira correta". Use otimizações como essa, que tornarão seus programas mais complicados somente quando você realmente precisar deles.fonte
O modelo conceitual será parecido com este, que é muito pouco ortodoxo para dizer menos:
O modelo físico terá esta aparência, o que é confuso para dizer menos (as pessoas pensam que é M: M, a menos que vejam de perto):
Minha sugestão:
Se desejar, muitas colunas (FK ou outras) que não se aplicam à maioria dos alunos, separe as tabelas em tabelas de funções com 1: 1 rels. Mas não é por serem FK, é porque as colunas não se aplicam à maioria das linhas.
Caso contrário , o FK anulável é uma parte normal de um banco de dados e as tabelas de junção geralmente são para M: M rels.
Os usos comuns de rels 1: 1 são para tabelas de funções com colunas que se aplicam apenas se a entidade for de um determinado tipo e extrair colunas BLOB por considerações de desempenho ou armazenamento. Avodar valores nulos em FKs não é um uso comum para isso.
fonte
Além de outras respostas, gostaria de salientar que um valor nulo para a chave estrangeira é ambíguo. Quer dizer:
1) A escola do aluno (se houver) é desconhecida (este é o significado padrão de 'nulo' - o valor é desconhecido)
2) Sabe-se se o aluno tem ou não uma escola e eles não têm
Se você usar o significado padrão de nulo, como você representaria "o aluno não tem escola" em seu modelo de chave estrangeira. Nesse caso, você provavelmente teria que criar uma entrada "sem escola", com seu próprio ID na tabela da escola. (Não é ideal)
fonte
NULL
, pode significar: 1) Valor desconhecido. 2) Valor indisponível ou retido. 3) Atributo não aplicável (acho que essa interpretação significa que você pode especificar aNULL
para uma chave estrangeira).As tabelas de banco de dados têm essa coisa legal chamada restrições. Portanto, é muito fácil criar na tabela de interseção que permite que apenas 1 de cada aluno apareça na tabela, mas muitas escolas nessa tabela. Efetivamente, dando-lhe uma
A teoria é boa, mas no final você vai modelar seu banco de dados após as perguntas que está fazendo.
Se você deseja questionar frequentemente com a pergunta: "quais alunos estão na minha escola", você realmente deseja consultar toda a tabela de alunos ou ter uma tabela de interseção fácil.
Nos bancos de dados: otimize para as perguntas que você faz.
fonte
Há um caso de uso em que o uso de uma terceira tabela pode realmente fazer sentido. O exemplo pode parecer puramente hipotético, mas espero que ilustre bem meu argumento. Suponhamos que você adicione mais colunas à
students
tabela e, em algum momento, decida impor exclusividade nos registros por meio do índice composto em várias colunas. É muito provável que você tenha que incluir aschool_id
coluna também, e aqui as coisas começam a ficar confusas. Devido à maneira como o SQL foi projetado,school_id
éNULL
possível inserir vários registros idênticos onde for . Faz todo o sentido do ponto de vista técnico, mas é contra-intuitivo e pode levar a resultados inesperados. Por outro lado, aplicar a exclusividade na mesa de interseção é fácil.Eu tive que modelar esse relacionamento "opcional" recentemente, onde o requisito para uma restrição de exclusividade era devido a uma coluna de carimbo de data / hora. Deixar a chave estrangeira anulável na tabela repentinamente leva à possibilidade de inserir registros com o mesmo carimbo de data / hora (vamos supor que seja um padrão, definido em registros que ainda não foram auditados / aprovados) - e a única saída é remover coluna anulável.
Então, como você pode ver, é um caso bastante específico e, como outros observaram, na maioria das vezes você estaria perfeitamente bem com todos os
NULL
valores. Realmente depende dos requisitos específicos do seu modelo.fonte
Além das muitas boas sugestões já enviadas, pessoalmente não sou fã de chaves estrangeiras, a menos que sejam realmente necessárias. Primeiro, há o relacionamento M: M que você está referenciando. Além disso, chamar uma chave estrangeira e, assim, puxar os dados da tabela para suas consultas, introduz mais complexidade e, dependendo do tamanho da tabela, desempenho mais lento. Como já foi dito, os campos FK anuláveis não podem ser suportados e podem criar problemas de integridade de dados.
Se você estiver definindo um estado em que a escola do aluno é desconhecida ou vazia, o NULL não diferencia essas condições. (novamente, voltamos à integridade dos dados.) A sugestão da tabela de funções de Tulains é elegante e permite valores nulos de maneira limpa.
fonte