Desvantagens de usar uma chave estrangeira anulável em vez de criar uma tabela de interseção


15

Digamos que eu tenha o seguinte diagrama de ER:

insira a descrição da imagem aqui

Agora, se eu representasse o relacionamento usando uma chave estrangeira de Schoolin Student, eu poderia ter NULLvalores (porque a Student não precisa pertencer a a School), por exemplo:

insira a descrição da imagem aqui

Portanto, a maneira correta (com base no que li) é criar uma tabela de interseção para representar o relacionamento, por exemplo:

insira a descrição da imagem aqui

Dessa forma, nenhum NULLvalor 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_Studenttabela, o que tornava o relacionamento muitos para muitos. A chave primária correta deveria ter sido student_id:

insira a descrição da imagem aqui


7
Não existe um caminho "correto". Existe exatamente o melhor para suas necessidades.
MetaFight #

1
Concordo com Doc sobre a premissa falsa, mas talvez ainda esteja claro o suficiente para responder?
MetaFight 03/11

Existe uma premissa falsa, mas é fácil o bastante esclarecer e explicar a diferença.

Recuei meu voto apertado, mas a frase "Então, a maneira correta (com base no que li) é criar uma tabela de interseção para representar o relacionamento" me dá a impressão de que você deve nos dizer qual fonte de conexão disse que essa é a " Maneira correta. Em todos os livros que li antes, o caminho canônico para os relacionamentos 1: n é uma única chave estrangeira. Ou você entendeu mal alguma coisa?
Doc Brown

@ Doc Brown Não me lembro de onde li, mas tenho certeza de que diz que uma tabela de interseção era a maneira correta. De qualquer forma, você pode me dar o nome de um livro que diz que um relacionamento 1: n (com participação opcional no lado: 1) deve ser representado usando uma única chave estrangeira, estou interessado em ler o que eles dizem sobre esse assunto.
Tom

Respostas:


18

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.


Portanto, se estou modelando um relacionamento um para muitos (com participação opcional no lado: 1), devo usar uma chave estrangeira, apesar de poder ter NULLvalores?
Tom

1
@ Tom sim, é exatamente assim que modelá-lo. Embora tecnicamente seja possível usar uma tabela de junção, o modelo de dados permite muitos a muitos, assim você precisará de acionadores e lógica de banco de dados para evitar isso. É melhor restringir o relacionamento de uma maneira que seja impossível adicionar dados incorretos.

1
Eu editei a minha pergunta. Eu apenas criei student_iduma chave primária na School_has_Studenttabela, que manteve o relacionamento como um para muitos. Quais são as desvantagens desse método ao usar uma chave estrangeira?
Tom

@ Tom eu editei minha resposta.

6

Você escreveu em um comentário acima:

o livro "Fundamentos dos sistemas de banco de dados" [...] diz que é recomendável usar uma tabela de interseção se houver muitos valores NULL na coluna de chave estrangeira (por exemplo: se 98% dos funcionários não gerencie um departamento)

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}:nrelacionamentos 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.


Você está assumindo muito sobre a implementação do banco de dados, especialmente considerando que o OP não mencionou um específico. É mais do que provável que o banco de dados seja inteligente o suficiente para usar apenas uma pequena quantidade de espaço para colunas esparsas.
Gardenhead 4/11

@ Gardenhead: o que faz você acreditar que isso é "mais do que provável"?
Doc Brown

O fato de os bancos de dados existirem há décadas e serem altamente otimizados, pois são um componente crítico da maioria das infraestruturas.
precisa saber é o seguinte

@ Gardenhead: parece-me que você está fazendo muito mais suposições injustificadas do que eu. No entanto, veja minha edição.
Doc Brown

2

O modelo conceitual será parecido com este, que é muito pouco ortodoxo para dizer menos:

insira a descrição da imagem aqui

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):

insira a descrição da imagem aqui

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.

insira a descrição da imagem aqui


2

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)


2
O livro "Fundamentos dos sistemas de banco de dados" menciona que existem 3 interpretações para 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 a NULLpara uma chave estrangeira).
Tom

1
Essa é uma lista útil, mas a semântica de null (ou qualquer valor realmente) é definível pelo usuário. Ou seja, pode significar o que o designer diz que significa, não se limitando a essa lista. A questão é como distinguir significados diferentes quando mais de um pode ser necessária (ou mesmo salvo involuntariamente)
Brad Thomas

Então, você está sugerindo que eu deveria criar uma tabela de interseção em vez de usar uma chave estrangeira anulável?
Tom

@ Tom Sim, eu acredito que é melhor neste caso
Brad Thomas

@BradThomas - para evitar a mesma ambiguidade ao usar uma tabela de interseção, você representaria o caso 2 (sabe-se que o aluno não tem escola) por um registro na tabela de interseção com um School_ID NULL?
Andrew

1

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.


0

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 à studentstabela 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 a school_idcoluna também, e aqui as coisas começam a ficar confusas. Devido à maneira como o SQL foi projetado, school_idé NULLpossí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 NULLvalores. Realmente depende dos requisitos específicos do seu modelo.


0

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.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.