Projetando uma estrutura de banco de dados de amizades: Devo usar uma coluna de valores múltiplos?

9

Digamos que eu tenha uma tabela chamada User_FriendList, que tenha as seguintes características:

CREATE TABLE User_FriendList (
    ID ...,
    User_ID...,
    FriendList_IDs...,
    CONSTRAINT User_Friendlist_PK PRIMARY KEY (ID)
);

E suponhamos que a referida tabela contenha os seguintes dados:

 + ---- + --------- + --------------------------- +
 | ID | ID do usuário | ID da lista de amigos             |
 + ---- + --------- + --------------------------- +
 | 1 | 102 2: 15: 66: 35: 26: 17: |
 + ---- + --------- + --------------------------- +
 | 2 114 1: 12: 63: 33: 24: 16: 102 |
 + ---- + --------- + --------------------------- +
 | 3 117 6: 24: 52: 61: 23: 90: 97: 118 |
 + ---- + --------- + --------------------------- +

Nota: O ":" (dois pontos) é o delimitador ao explodir no PHP em um array.

Questões

Assim:

  • Essa é uma maneira conveniente de "armazenar" o IDsde a FriendList?

  • Ou, em vez disso, devo ter linhas individuais com apenas um único FriendIdvalor em cada uma delas e, quando precisar recuperar todas as linhas de uma determinada lista , basta executar uma consulta como SELECT * FROM UserFriendList WHERE UserId = 1?

yeln
fonte
3
Eu recomendo que você leia isto: stackoverflow.com/questions/3653462/...
tombom
É uma maneira conveniente de armazenar os IDs, desde que você não planeje fazer nada com eles e não se preocupe particularmente com a qualidade dos dados.
22418 mustaccio
Acho que codedodle.com/2014/12/social-network-friends-database.html poderia ser uma das melhores soluções.
Gupta

Respostas:

19

Gerenciando uma informação individual

Supondo que, no seu domínio comercial,

  • um usuário pode ter zero ou um ou muitos amigos ;
  • um amigo deve primeiro ser registrado como um usuário ; e
  • você pesquisará e / ou adicionará, e / ou removerá e / ou modificará valores únicos de uma Lista de Amigos ;

em seguida, cada um datum específico reunidos na Friendlist_IDscoluna de valor múltiplo representa um pedaço de informação que carrega um significado muito exata. Portanto, a referida coluna

  • implica um grupo adequado de restrições explícitas e
  • seus valores têm o potencial de serem manipulados individualmente por meio de várias operações relacionais (ou combinações das mesmas).

Resposta curta

Conseqüentemente, você deve reter cada um dos Friendlist_IDsvalores em (a) uma coluna que aceita exclusivamente um único valor por linha em (b) uma tabela que represente o tipo de associação em nível conceitual que pode ocorrer entre os Usuários , ou seja, uma Amizade - como Vou exemplificar nas seções a seguir.

Dessa forma, você será capaz de lidar com (i) a referida tabela como uma relação matemática e (ii) a referida coluna como um atributo da relação matemática - tanto quanto o MySQL e seu dialeto SQL permitirem, é claro -.

Por quê?

Como o modelo relacional de dados , criado pelo Dr. E. F. Codd , exige ter tabelas compostas de colunas que contêm exatamente um valor do domínio ou tipo aplicável por linha; portanto, declarar uma tabela com uma coluna que pode conter mais de um valor do domínio ou tipo em questão (1) não representa uma relação matemática e (2) não permitiria obter as vantagens propostas no referencial teórico acima mencionado.

Modelando amizades entre usuários : definindo primeiro as regras do ambiente de negócios

Eu recomendo começar a modelar um banco de dados delimitando - antes de mais nada - o esquema conceitual correspondente em virtude da definição das regras de negócios relevantes que, entre outros fatores, devem descrever os tipos de inter-relações existentes entre os diferentes aspectos de interesse, ou seja, , os tipos de entidade aplicáveis e suas propriedades ; por exemplo:

  • Um usuário é identificado principalmente por seu UserId
  • Um usuário é identificado alternadamente pela combinação de seu nome , sobrenome , sexo e data de nascimento
  • Um usuário é identificado alternadamente por seu nome de usuário
  • Um usuário é o solicitante de zero ou uma ou muitas amizades
  • Um usuário é o destinatário de zero ou uma ou muitas amizades
  • Uma amizade é identificada principalmente pela combinação de seu RequesterId e seu AddresseeId

Diagrama do IDEF1X expositivo

Dessa maneira, consegui derivar o diagrama IDEF1X 1 mostrado na Figura 1 , que integra a maioria das regras formuladas anteriormente:

Figura 1. Amizades do usuário Diagrama IDEF1X

Conforme representado, Solicitante e Destinatário são denotações que expressam as Funções desempenhadas pelos Usuários específicos que participam de uma determinada Amizade .

Sendo assim, o tipo de entidade Amizade retrata um tipo de associação da proporção de cardinalidade muitos para muitos (M: N) que pode envolver ocorrências diferentes do mesmo tipo de entidade, ou seja, Usuário . Como tal, é um exemplo do construto clássico conhecido como "Lista de materiais" ou "Explosão de peças".


1 Definição de Integração para Modelagem de Informações ( IDEF1X ) é uma técnica altamente recomendável que foi estabelecida como padrão em dezembro de 1993 pelo Instituto Nacional de Padrões e Tecnologia dos EUA (NIST). É solidamente baseado em (a) o material teórico inicial criado pelo único autordo modelo relacional, ou seja, Dr. EF Codd ; (b) avisão de dados entre entidades e relacionamentos , desenvolvida pelo Dr. PP Chen ; e também (c) a Logical Database Design Technique, criada por Robert G. Brown.


Projeto lógico SQL-DDL ilustrativo

Então, a partir do diagrama IDEF1X apresentado acima, declarar um arranjo DDL como o que se segue é muito mais "natural":

-- You should determine which are the most fitting 
-- data types and sizes for all the table columns 
-- depending on your business context characteristics.

-- At the physical level, you should make accurate tests 
-- to define the mostconvenient INDEX strategies based on 
-- the pertinent query tendencies.

-- As one would expect, you are free to make use of 
-- your preferred (or required) naming conventions. 

CREATE TABLE UserProfile ( -- Represents an independent entity type.
    UserId          INT      NOT NULL,
    FirstName       CHAR(30) NOT NULL,
    LastName        CHAR(30) NOT NULL,
    BirthDate       DATE     NOT NULL,
    GenderCode      CHAR(3)  NOT NULL,
    Username        CHAR(20) NOT NULL,
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT UserProfile_PK  PRIMARY KEY (UserId),
    CONSTRAINT UserProfile_AK1 UNIQUE ( -- Composite ALTERNATE KEY.
        FirstName,
        LastName,
        GenderCode,
        BirthDate
    ),
    CONSTRAINT UserProfile_AK2 UNIQUE (Username) -- Single-column ALTERNATE KEY.
);

CREATE TABLE Friendship ( -- Stands for an associative entity type.
    RequesterId     INT      NOT NULL,
    AddresseeId     INT      NOT NULL, -- Fixed with a well-delimited data type.
    CreatedDateTime DATETIME NOT NULL,
    --
    CONSTRAINT Friendship_PK            PRIMARY KEY (RequesterId, AddresseeId), -- Composite PRIMARY KEY.
    CONSTRAINT FriendshipToRequester_FK FOREIGN KEY (RequesterId)
        REFERENCES UserProfile (UserId),
    CONSTRAINT FriendshipToAddressee_FK FOREIGN KEY (AddresseeId)
        REFERENCES UserProfile (UserId)
);

Desta forma:

  • cada tabela base representa um tipo de entidade individual;
  • cada coluna representa uma única propriedade do respectivo tipo de entidade;
  • um específico tipo de dados que um é fixo em cada coluna , a fim de garantir que todos os valores que contém pertencem a uma específica e bem definida conjunto , seja INT, DATETIME, CHAR, etc .; e
  • várias restrições b são configuradas (declarativamente) para garantir que as asserções na forma de linhas retidas em todas as tabelas atendam às regras de negócios determinadas no esquema conceitual.

Vantagens de uma coluna de valor único

Como demonstrado, você pode, por exemplo:

  • Aproveite a integridade referencial imposta pelo sistema de gerenciamento de banco de dados (DBMS por brevidade) para a Friendship.AddresseeIdcoluna, pois a restrição como uma FOREIGN KEY (FK por brevidade) que faz uma referência à UserProfile.UserIdcoluna garante que todo valor aponte para uma linha existente .

  • Criar um composto chave primária (PK) composta da combinação de colunas (Friendship.RequesterId, Friendship.AddresseeId), ajudando a elegantemente distinguir todas as linhas inseridas e, naturalmente, proteger a sua singularidade .

    Obviamente, isso significa que o anexo de uma coluna extra para valores substitutos atribuídos pelo sistema (por exemplo, um configurado com a propriedade IDENTITY no Microsoft SQL Server ou com o atributo AUTO_INCREMENT no MySQL) e o INDEX auxiliar são totalmente supérfluos .

  • Restrinja os valores retidos Friendship.AddresseeIdpara um tipo de dados preciso c (que deve corresponder, por exemplo, ao estabelecido para UserProfile.UserId, neste caso, INT), permitindo que o DBMS cuide da validação automática pertinente .

    Esse fator também pode ajudar a (a) utilizar as funções do tipo interno correspondentes e (b) otimizar o uso do espaço em disco .

  • Otimize a recuperação de dados no nível físico, configurando INDEXes subordinados pequenos e rápidos para a Friendship.AddresseeIdcoluna, pois esses elementos físicos podem ajudar substancialmente a acelerar as consultas que envolvem a coluna.

    Certamente, você pode, por exemplo, colocar um INDEX de coluna única Friendship.AddresseeIdapenas, um de coluna múltipla que inclua Friendship.RequesterIde Friendship.AddresseeId, ou ambos.

  • Evite a complexidade desnecessária introduzida pela “pesquisa” de valores distintos que são coletados na mesma coluna (provavelmente duplicados, digitados incorretamente etc.), um curso de ação que acabaria por retardar o funcionamento do seu sistema, porque você precisa recorrer a métodos não relacionais que consomem recursos e tempo para realizar a tarefa.

Portanto, há vários motivos que exigem a análise cuidadosa do ambiente de negócios relevante para marcar com precisão o tipo d de cada coluna da tabela.

Conforme exposto, o papel desempenhado pelo criador do banco de dados é primordial para fazer o melhor uso (1) dos benefícios de nível lógico oferecidos pelo modelo relacional e (2) dos mecanismos físicos fornecidos pelo DBMS de sua escolha.


a , b , c , d Evidentemente, ao trabalhar com plataformas SQL (por exemplo, Firebird e PostgreSQL ) que suportam a criação de DOMAIN (umrecurso relacional distinto), você pode declarar colunas que aceitam apenas valores que pertencem a seus respectivos compartilhado) DOMAINs.


Um ou mais programas aplicativos que compartilham o banco de dados em consideração

Quando você precisar empregar arrayso código do (s) programa (s) aplicativo (s) acessando o banco de dados, basta recuperar o (s) conjunto (s) de dados relevante (s) na íntegra e, em seguida, "vinculá-lo (s) à estrutura de código relacionada ou executar o processo (s) de aplicativos associado (s) que devem ocorrer.

Benefícios adicionais de colunas com valor único: as extensões da estrutura do banco de dados são muito mais fáceis

Outra vantagem de manter o AddresseeIdponto de dados em sua coluna reservada e com o tipo correto é que ele facilita consideravelmente a extensão da estrutura do banco de dados, como exemplificarei abaixo.

Progressão do cenário: Incorporando o conceito Status da Amizade

Como as Amizades podem evoluir ao longo do tempo, talvez seja necessário acompanhar esse fenômeno; portanto, você deverá (i) expandir o esquema conceitual e (ii) declarar mais algumas tabelas no layout lógico. Portanto, vamos organizar as próximas regras de negócios para delinear as novas incorporações:

  • Uma Amizade mantém um para muitos Estatutos de Amizade
  • Um FriendshipStatus é identificado principalmente pela combinação de RequesterId , AddresseeId e SpecifiedDateTime
  • Um usuário especifica zero-um-ou-muitos FriendshipStatuses
  • Um Status classifica zero-um-ou-muitos FriendshipStatuses
  • Um Status é identificado principalmente por seu StatusCode
  • Um status é alternadamente identificado por seu nome

Diagrama IDEF1X estendido

Sucessivamente, o diagrama IDEF1X anterior pode ser estendido para incluir os novos tipos de entidade e tipos de inter-relacionamento descritos acima. Um diagrama representando os elementos anteriores associados aos novos é apresentado na Figura 2 :

Figura 2. Diagrama do status da amizade IDEF1X

Adições à estrutura lógica

Posteriormente, podemos prolongar o layout DDL com as seguintes declarações:

--
CREATE TABLE MyStatus ( -- Denotes an independent entity type.
    StatusCode CHAR(1)  NOT NULL,
    Name       CHAR(30) NOT NULL,
    --
    CONSTRAINT MyStatus_PK PRIMARY KEY (StatusCode),
    CONSTRAINT MyStatus_AK UNIQUE      (Name) -- ALTERNATE KEY.
); 

CREATE TABLE FriendshipStatus ( -- Represents an associative entity type.
    RequesterId       INT      NOT NULL,
    AddresseeId       INT      NOT NULL,
    SpecifiedDateTime DATETIME NOT NULL,
    StatusCode        CHAR(1)  NOT NULL,
    SpecifierId       INT      NOT NULL,
    --
    CONSTRAINT FriendshipStatus_PK             PRIMARY KEY (RequesterId, AddresseeId, SpecifiedDateTime), -- Composite PRIMARY KEY.
    CONSTRAINT FriendshipStatusToFriendship_FK FOREIGN KEY (RequesterId, AddresseeId)
        REFERENCES Friendship  (RequesterId, AddresseeId), -- Composite FOREIGN KEY.
    CONSTRAINT FriendshipStatusToMyStatus_FK   FOREIGN KEY (StatusCode)
        REFERENCES MyStatus    (StatusCode),
    CONSTRAINT FriendshipStatusToSpecifier_FK  FOREIGN KEY (SpecifierId)
        REFERENCES UserProfile (UserId)      
);

Consequentemente, toda vez que o status de uma determinada amizade precisar ser atualizado, os usuários precisarão apenas INSERIR uma nova FriendshipStatuslinha, contendo:

  • o adequado RequesterIde os AddresseeIdvalores - retirados da linha em questão - Friendship;

  • o novo e significativo StatusCodevalor - retirado de MyStatus.StatusCode-;

  • o instante exato da INSERÇÃO, ou seja, - de SpecifiedDateTimepreferência , usando uma função de servidor para que você possa recuperá-la e retê-la de maneira confiável -; e

  • o SpecifierIdvalor que indicaria o respectivo UserIdque inseriu o novo FriendshipStatusno sistema - idealmente, com a ajuda dos recursos de seus aplicativos -.

Nessa medida, suponhamos que a MyStatustabela inclui os seguintes dados -com valores de PK que são (a) pelo usuário final, app programmer- e amigável-DBA e (b) pequena e rápida em termos de bytes no físico nível de implementação -:

 + -—————————- + -————————— +
 | StatusCode | nome       |
 + -—————————- + -————————— +
 | R Solicitado |
 + ------------ + ----------- +
 | A Aceito |
 + ------------ + ----------- +
 | D Recusado |
 + ------------ + ----------- +
 | B Bloqueado |
 + ------------ + ----------- +

Portanto, a FriendshipStatustabela pode conter dados como mostrado abaixo:

 + -——————————- + -——————————- + -——————————————— ———- + -—————————- + -—————————— +
 | RequesterId | AddresseeId | SpecifiedDateTime        | StatusCode | SpecifierId |
 + -——————————- + -——————————- + -——————————————— ———- + -—————————- + -—————————— +
 | 1750 1748 01-04-2016 16: 58: 12.000 | R 1750
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 1748 02-04-2016 09: 12: 05.000 | A 1748
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 1748 04-04-2016 10: 57: 01.000 | B 1750
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 1748 07-04-2016 07: 33: 08.000 | R 1748
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 1750 1748 08-04-2016 12: 12: 09.000 | A 1750
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +

Como você pode ver, pode-se dizer que a FriendshipStatustabela serve para o propósito de compreender uma série temporal .


Postagens relevantes

Você também pode estar interessado em:

  • Esta resposta, na qual sugiro um método básico para lidar com um relacionamento muitos-para-muitos comum entre dois tipos de entidades diferentes.
  • O diagrama IDEF1X mostrado na Figura 1 que ilustra essa outra resposta . Preste atenção especial aos tipos de entidade denominados Casamento e Progênie , porque são mais dois exemplos de como lidar com o "Problema de explosão de peças".
  • Este post que apresenta uma breve deliberação sobre a retenção de diferentes informações em uma única coluna.
MDCCL
fonte