Quando devo usar um relacionamento um para um?

93

Desculpe por essa pergunta noob, mas há alguma necessidade real de usar relacionamento um-para-um com as tabelas em seu banco de dados? Você pode implementar todos os campos necessários dentro de uma tabela. Mesmo se os dados se tornarem muito grandes, você pode enumerar os nomes das colunas de que precisa na SELECTinstrução em vez de usar SELECT *. Quando você realmente precisa dessa separação?

Pavel Shchegolevatykh
fonte

Respostas:

109

1 a 0..1

  • O "1 a 0..1" entre super e subclasses é usado como parte da estratégia "todas as classes em tabelas separadas" para implementar a herança .

  • Um "1 a 0..1" pode ser representado em uma única tabela com a parte "0..1" coberta por campos que podem ser NULL. No entanto, se o relacionamento for principalmente de "1 para 0" com apenas algumas linhas de "1 para 1", dividir a parte "0..1" em uma tabela separada pode economizar alguns benefícios de armazenamento (e desempenho de cache). Alguns bancos de dados são mais econômicos no armazenamento de NULLs do que outros, portanto, um "ponto de corte" onde essa estratégia se torna viável pode variar consideravelmente.

1 para 1

  • O verdadeiro "1 para 1" particiona verticalmente os dados, o que pode ter implicações para o cache. Os bancos de dados geralmente implementam caches no nível da página, não no nível dos campos individuais, portanto, mesmo se você selecionar apenas alguns campos de uma linha, normalmente toda a página à qual a linha pertence será armazenada em cache. Se uma linha for muito larga e os campos selecionados relativamente estreitos, você acabará armazenando em cache muitas informações de que realmente não precisa. Em uma situação como essa, pode ser útil particionar verticalmente os dados, de forma que apenas a parte ou as linhas mais estreitas e usadas com mais frequência sejam armazenadas em cache, de modo que mais delas possam caber no cache, tornando o cache efetivamente "maior".

  • Outro uso do particionamento vertical é alterar o comportamento de bloqueio: os bancos de dados normalmente não podem ser bloqueados no nível de campos individuais, apenas as linhas inteiras. Ao dividir a linha, você está permitindo que um bloqueio ocorra em apenas uma de suas metades.

  • Os gatilhos também são normalmente específicos da tabela. Embora você possa teoricamente ter apenas uma tabela e fazer com que o gatilho ignore a "metade errada" da linha, alguns bancos de dados podem impor limites adicionais sobre o que um gatilho pode ou não fazer, o que pode tornar isso impraticável. Por exemplo, o Oracle não permite que você modifique a tabela em mutação - por ter tabelas separadas, apenas uma delas pode estar em mutação, então você ainda pode modificar a outra a partir de seu gatilho.

  • Tabelas separadas podem permitir uma segurança mais granular.

Essas considerações são irrelevantes na maioria dos casos, portanto, na maioria dos casos, você deve considerar mesclar as tabelas "1 a 1" em uma única tabela.

Branko Dimitrijevic
fonte
21

Se os dados em uma tabela estiverem relacionados, mas não "pertencerem" à entidade descrita pela outra, então isso é um candidato a mantê-los separados.

Isso pode fornecer vantagens no futuro, se os dados separados também precisarem estar relacionados a alguma outra entidade.

Sepster
fonte
21

Se você colocar duas tabelas um-para-um em um, é provável que você tenha problemas de semântica. Por exemplo, se cada dispositivo tiver um controlador remoto, não parece muito bom colocar o dispositivo e o controlador remoto com seu conjunto de características em uma tabela. Você pode até mesmo gastar tempo tentando descobrir se um determinado atributo pertence ao dispositivo ou ao controle remoto.

Pode haver casos em que metade das colunas ficará vazia por um longo tempo ou nunca será preenchida. Por exemplo, um carro pode ter um trailer com várias características ou pode não ter nenhuma. Portanto, você terá muitos atributos não utilizados.

Se sua tabela tiver 20 atributos e apenas 4 deles forem usados ​​ocasionalmente, faz sentido dividir a tabela em 2 para problemas de desempenho.

Nesses casos, não é bom ter tudo em uma mesa. Além disso, não é fácil lidar com uma tabela de 45 colunas!

superM
fonte
18

Meus 2 centavos.

Eu trabalho em um lugar onde todos nós desenvolvemos em um grande aplicativo, e tudo é um módulo. Por exemplo, temos uma userstabela e temos um módulo que adiciona detalhes do Facebook para um usuário, outro módulo que adiciona detalhes do Twitter para um usuário. Poderíamos decidir desconectar um desses módulos e remover todas as suas funcionalidades de nosso aplicativo. Nesse caso, cada módulo adiciona sua própria tabela com relacionamentos 1: 1 à userstabela global , assim:

create table users ( id int primary key, ...);
create table users_fbdata ( id int primary key, ..., constraint users foreighn key ...)
create table users_twdata ( id int primary key, ..., constraint users foreighn key ...)
santiago arizti
fonte
13

O momento mais sensato para usar isso seria se houvesse dois conceitos separados que só se relacionariam dessa maneira. Por exemplo, um carro pode ter apenas um motorista atual, e o motorista só pode dirigir um carro por vez - então a relação entre os conceitos de carro e motorista seria de 1 a 1. Aceito que este é um exemplo inventado para demonstrar o ponto.

Outra razão é que você deseja especializar um conceito de maneiras diferentes. Se você tem uma tabela Person e deseja adicionar o conceito de diferentes tipos de Person, como Employee, Customer, Shareholder - cada um deles precisaria de conjuntos diferentes de dados. Os dados semelhantes entre eles estariam na tabela Pessoa, as informações do especialista estariam nas tabelas específicas para Cliente, Acionista, Funcionário.

Alguns mecanismos de banco de dados lutam para adicionar com eficiência uma nova coluna a uma tabela muito grande (muitas linhas) e tenho visto tabelas de extensão usadas para conter a nova coluna, em vez de a nova coluna ser adicionada à tabela original. Este é um dos usos mais suspeitos de tabelas adicionais.

Você também pode decidir dividir os dados para um único conceito entre duas tabelas diferentes para problemas de desempenho ou legibilidade, mas este é um caso razoavelmente especial se você estiver começando do zero - esses problemas aparecerão mais tarde.

Fenton
fonte
5

não muito frequentemente.

você pode encontrar algum benefício se precisar implementar alguma segurança - para que alguns usuários possam ver algumas das colunas (tabela 1), mas não outras (tabela 2).

é claro que alguns bancos de dados (Oracle) permitem que você faça esse tipo de segurança na mesma tabela, mas alguns outros não.

Randy
fonte
5

Você está se referindo à normalização do banco de dados. Um exemplo que posso pensar em um aplicativo que mantenho é o Items. O aplicativo permite que o usuário venda muitos tipos diferentes de itens (ou seja, InventoryItems, NonInventoryItems, ServiceItems, etc ...). Embora eu pudesse armazenar todos os campos exigidos por cada item em uma tabela de itens, é muito mais fácil manter uma tabela de item de base que contém campos comuns a todos os itens e, em seguida, tabelas separadas para cada tipo de item (ou seja, estoque, não estoque, etc.) que contêm campos específicos apenas para aquele tipo de item. Então, a tabela de itens teria uma chave estrangeira para o tipo de item específico que representa. O relacionamento entre as tabelas de itens específicos e a tabela de itens de base seria um para um.

Abaixo, está um artigo sobre normalização.

http://support.microsoft.com/kb/283878

gafanhoto
fonte
3

Como acontece com todas as questões de design, a resposta é "depende".

Existem algumas considerações:

  • qual o tamanho da tabela (em termos de campos e linhas)? Pode ser inconveniente hospedar o nome e a senha de seus usuários com outros dados menos usados, tanto do ponto de vista de manutenção quanto de programação

  • Os campos da tabela combinada que possuem restrições podem se tornar complicados de gerenciar com o tempo. por exemplo, se um gatilho precisa ser disparado para um campo específico, isso acontecerá para cada atualização da tabela, independentemente de o campo ter sido afetado.

  • quão certo você tem de que o relacionamento será 1: 1? Como esta questão indica, as coisas podem complicar rapidamente.

Rob Allen
fonte
3

Outro caso de uso pode ser o seguinte: você pode importar dados de alguma fonte e atualizá-los diariamente, por exemplo, informações sobre livros. Em seguida, você adiciona dados sobre alguns livros. Então, faz sentido colocar os dados importados em outra tabela que não seus próprios dados.

Dirk
fonte
2

Normalmente encontro dois tipos gerais de relacionamento 1: 1 na prática:

  1. Relacionamentos IS-A, também conhecidos como relacionamentos de supertipo / subtipo. Isso ocorre quando um tipo de entidade é, na verdade, um tipo de outra entidade (EntityA IS A EntityB). Exemplos:

    • Entidade pessoal, com entidades separadas para Contador, Engenheiro, Vendedor, dentro da mesma empresa.
    • Entidade de item, com entidades separadas para Widget, RawMaterial, FinishedGood, etc.
    • Entidade de carro, com entidades separadas para Caminhão, Sedan, etc.

    Em todas essas situações, a entidade de supertipo (por exemplo, Pessoa, Item ou Carro) teria os atributos comuns a todos os subtipos e as entidades de subtipo teriam atributos exclusivos para cada subtipo. A chave primária do subtipo seria a mesma do supertipo.

  2. Relacionamentos de "chefe". É quando uma pessoa é o único chefe, gerente ou supervisor de uma unidade organizacional (departamento, empresa etc.). Quando há apenas um chefe permitido para uma unidade organizacional, há um relacionamento 1: 1 entre a entidade pessoal que representa o chefe e a entidade da unidade organizacional.

Tripartio
fonte
1
Eu gosto do segundo exemplo. Você pode ter a entidade "Departamento" e a entidade "Funcionário". Em um departamento, você tem muitos funcionários, e um funcionário pode trabalhar apenas em um departamento. Este é 1: n. Um funcionário pode ser supervisor de um departamento - apenas de um departamento, e o departamento tem apenas um supervisor. Assim, você acaba com duas tabelas conectadas por duas relações - 1: ne 1: 1.
cezar
2

Primeiro, acho que é uma questão de modelar e definir o que consiste em uma entidade separada. Suponha que você tenha customersum e apenas um único address. Claro que você poderia implementar tudo em uma única tabela customer, mas se, no futuro, permitir que ele tenha 2 ou mais endereços, você precisará refatorar isso (não é um problema, mas tome uma decisão consciente).

Também posso pensar em um caso interessante não mencionado em outras respostas em que dividir a tabela pode ser útil:

Imagine, novamente, você tem customerscom um único addresscada, mas desta vez é opcional ter um endereço. Claro que você pode implementar isso como um monte de NULLcolunas -able, como ZIP,state,street. Mas suponha que, dado que você tem um endereço, o estado não é opcional, mas o ZIP é. Como modelar isso em uma única tabela? Você poderia usar uma restrição na customertabela, mas é muito mais fácil dividir em outra tabela e tornar a Foreign_key NULLable. Dessa forma, seu modelo é muito mais explícito ao dizer que a entidade address é opcional e que ZIPé um atributo opcional dessa entidade.

polvoazul
fonte
0

No meu tempo de programação, encontrei isso apenas em uma situação. Que é quando há um relacionamento de 1 para muitos e 1 para 1 entre as mesmas 2 entidades ("Entidade A" e "Entidade B").

Quando "Entidade A" tem várias "Entidades B" e "Entidade B" tem apenas 1 "Entidade A" e "Entidade A" tem apenas 1 "Entidade B" atual e "Entidade B" tem apenas 1 "Entidade A".

Por exemplo, um carro pode ter apenas um motorista atual, e o motorista só pode dirigir um carro por vez - então a relação entre os conceitos de carro e motorista seria de 1 para 1. - Eu peguei emprestado este exemplo da resposta de @Steve Fenton

Onde um motorista pode dirigir vários carros, mas não ao mesmo tempo. Portanto, as entidades Car e Driver são 1 para muitos ou muitos para muitos. Mas se precisamos saber quem é o driver atual, então também precisamos da relação 1 para 1.

Jo Smo
fonte
0

Outro caso de uso pode ser se o número máximo de colunas na tabela do banco de dados for excedido. Então você pode entrar em outra mesa usando OneToOne

db303
fonte