Progettare una struttura di database di amicizie: dovrei usare una colonna multivalore?


9

Supponiamo di avere una tabella chiamata User_FriendList, che presenta le seguenti caratteristiche:

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

E supponiamo che detta tabella contenga i seguenti dati:

 + ---- + --------- + --------------------------- +
 | ID | ID_utente | Friendlist_IDs             |
 + ---- + --------- + --------------------------- +
 | 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: ":" (due punti) è il delimitatore quando esplode in PHP in un array.

Domande

Così:

  • È un modo conveniente per "memorizzare" il IDsdi a FriendList?

  • Oppure, invece, dovrei avere singole righe con un solo FriendIdvalore in ciascuna di esse e, quando devo recuperare tutte le righe di un determinato elenco , eseguire semplicemente una query come SELECT * FROM UserFriendList WHERE UserId = 1?


3
Vi consiglio di leggere questo: stackoverflow.com/questions/3653462/...
tombom

È un modo un po 'conveniente per archiviare gli ID, purché tu non abbia intenzione di fare nulla con essi e non ti interessi particolarmente alla qualità dei dati.
Mustaccio,

Penso che codedodle.com/2014/12/social-network-friends-database.html potrebbe essere una delle migliori soluzioni.
Gupta,

Risposte:


19

Gestire una singola informazione

Supponendo che, nel tuo dominio aziendale,

  • un utente può avere zero-uno-o-molti amici ;
  • un amico deve prima essere registrato come utente ; e
  • cercherai e / o aggiungerai, e / o rimuoverai e / o modificherai singoli valori di un Elenco di amici ;

quindi ogni dato specifico raccolto nella Friendlist_IDscolonna multivalore rappresenta un'informazione separata che ha un significato molto esatto. Pertanto, detta colonna

  • comporta un gruppo adeguato di vincoli espliciti e
  • i suoi valori hanno il potenziale di essere manipolati individualmente per mezzo di diverse operazioni relazionali (o loro combinazioni).

Risposta breve

Di conseguenza, dovresti conservare ciascuno dei Friendlist_IDsvalori in (a) una colonna che accetta esclusivamente un valore unico per riga in (b) una tabella che rappresenta il tipo di associazione a livello concettuale che può avere luogo tra Utenti , ovvero un'amicizia, come Esemplificerò nelle seguenti sezioni:

In questo modo, sarai in grado di gestire (i) detta tabella come relazione matematica e (ii) detta colonna come attributo di relazione matematica - tanto quanto MySQL e il suo dialetto SQL lo consentono, ovviamente—.

Perché?

Perché il modello relazionale di dati , creato dal Dr. E. F. Codd , richiede di avere tabelle composte da colonne che contengano esattamente un valore del dominio o tipo applicabile per riga; pertanto, dichiarare una tabella con una colonna che può contenere più di un valore del dominio o del tipo in questione (1) non rappresenta una relazione matematica e (2) non consentirebbe di ottenere i vantaggi proposti nel suddetto quadro teorico.

Modellare le amicizie tra utenti : definire prima le regole dell'ambiente aziendale

Consiglio vivamente di iniziare a modellare un database che delimita - prima di ogni altra cosa - lo schema concettuale corrispondente in virtù della definizione delle pertinenti regole commerciali che, tra gli altri fattori, devono descrivere i tipi di interrelazioni esistenti tra i diversi aspetti di interesse, vale a dire , i tipi di entità applicabili e le loro proprietà ; per esempio:

  • Un utente è identificato principalmente dal suo ID utente
  • Un utente è alternativamente identificato dalla combinazione della sua FirstName , Cognome , Sesso , e Data di nascita
  • Un utente viene alternativamente identificato dal suo nome utente
  • Un utente è il richiedente di amicizie zero-uno-o-molte
  • Un utente è il destinatario di amicizie zero-uno-o-molte
  • Un'amicizia è principalmente identificato dalla combinazione della sua RequesterId e la sua AddresseeId

Diagramma IDEF1X dell'esposizione

In questo modo, sono stato in grado di derivare il diagramma IDEF1X 1 mostrato in Figura 1 , che integra la maggior parte delle regole precedentemente formulate:

Figura 1. Diagramma IDEF1X di amicizia degli utenti

Come illustrato, il richiedente e il destinatario sono denotazioni che esprimono i ruoli svolti dagli utenti specifici che prendono parte a una determinata amicizia .

Ciò premesso, il tipo di entità Amicizia rappresenta un tipo di associazione con un rapporto di cardinalità molti-a-molti (M: N) che può comportare diverse occorrenze dello stesso tipo di entità, ovvero Utente . In quanto tale, è un esempio del classico costrutto noto come "distinta materiali" o "esplosione delle parti".


1 Integration Definition for Information Modeling ( IDEF1X ) è una tecnica altamente raccomandabile che è stata stabilita come standard nel dicembre 1993 dal National Institute of Standards and Technology (NIST)degli Stati Uniti. È solidamente basato su (a) il materiale teorico iniziale creato dall'unico creatore del modello relazionale, cioè il Dr. EF Codd ; su (b) lavisione entità-relazione dei dati, sviluppata dal Dr. PP Chen ; e anche su (c) la tecnica di progettazione del database logico, creata da Robert G. Brown.


Progettazione logica illustrativa SQL-DDL

Quindi, dal diagramma IDEF1X presentato sopra, dichiarare una disposizione DDL come quella che segue è molto più "naturale":

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

In questo modo:

  • ogni tabella di base rappresenta un tipo di entità individuale;
  • ogni colonna rappresenta una sola proprietà del rispettivo tipo di entità;
  • uno specifico tipo di dati un è fissato per ogni colonna al fine di garantire che tutti i valori che contiene appartengono a una particolare e ben definito insieme , sia esso INT, DATETIME, CHAR, ecc .; e
  • più vincoli b sono configurati (in modo dichiarativo) al fine di garantire che le asserzioni sotto forma di righe conservate in tutte le tabelle soddisfino le regole aziendali determinate nello schema concettuale.

Vantaggi di una colonna a valore singolo

Come dimostrato, è possibile, ad esempio:

  • Sfrutta l' integrità referenziale applicata dal sistema di gestione del database (DBMS per brevità) per la Friendship.AddresseeIdcolonna, dal momento che vincolandola come FOREIGN KEY (FK per brevità) che fa un riferimento alla UserProfile.UserIdcolonna garantisce che ogni valore punta a una riga esistente .

  • Crea un PRIMARY KEY composito (PK) composto dalla combinazione di colonne (Friendship.RequesterId, Friendship.AddresseeId), contribuendo a distinguere elegantemente tutte le righe INSERITE e, naturalmente, proteggendo la loro unicità .

    Ovviamente, ciò significa che l'allegato di una colonna aggiuntiva per i valori surrogati assegnati dal sistema (ad esempio, uno impostato con la proprietà IDENTITY in Microsoft SQL Server o con l' attributo AUTO_INCREMENT in MySQL) e l'indice di assistenza è del tutto superfluo .

  • Limitare i valori conservati Friendship.AddresseeIda un preciso tipo di dati c (che dovrebbe corrispondere, ad esempio, a quello stabilito per UserProfile.UserId, in questo caso INT), lasciando che il DBMS si occupi della relativa validazione automatica .

    Questo fattore può anche aiutare a (a) utilizzare le corrispondenti funzioni del tipo incorporato e (b) ottimizzare l' utilizzo dello spazio su disco .

  • Ottimizza il recupero dei dati a livello fisico configurando INDICE subordinati piccoli e veloci per la Friendship.AddresseeIdcolonna, poiché questi elementi fisici possono aiutare sostanzialmente ad accelerare le query che coinvolgono detta colonna.

    Certamente, puoi, ad esempio, creare un INDICE a colonna singola per Friendship.AddresseeIdsolo, uno a più colonne che comprende Friendship.RequesterIde Friendship.AddresseeId, o entrambi.

  • Evita la complessità inutile introdotta dalla "ricerca" di valori distinti che vengono raccolti insieme nella stessa colonna (molto probabilmente duplicati, digitati in modo errato, ecc.), Un corso d'azione che alla fine rallenterebbe il funzionamento del tuo sistema, perché ricorrere a metodi non relazionali dispendiosi in termini di risorse e di tempo per svolgere tale compito.

Pertanto, ci sono molte ragioni che richiedono di analizzare attentamente l'ambiente aziendale rilevante al fine di contrassegnare con precisione il tipo d di ogni colonna della tabella.

Come spiegato, il ruolo svolto dal progettista del database è fondamentale per sfruttare al meglio (1) i vantaggi a livello logico offerti dal modello relazionale e (2) i meccanismi fisici forniti dal DBMS preferito.


a , b , c , d Evidentemente, quando si lavora con piattaforme SQL (ad esempio, Firebird e PostgreSQL ) che supportano la creazione di DOMAIN (una caratteristica relazionale distintiva), è possibile dichiarare colonne che accettano solo valori che appartengono ai rispettivi (opportunamente vincolati e talvolta condiviso) DOMINI.


Uno o più programmi applicativi che condividono il database in esame

Quando si deve impiegare arraysnel codice del programma applicativo (s) accesing il database, è semplicemente bisogno di recuperare il set di dati in questione (s) in pieno e poi “legare” lo (li) per la struttura del codice in materia o eseguire il processi che devono essere associati.

Ulteriori vantaggi delle colonne a valore singolo: le estensioni della struttura del database sono molto più semplici

Un altro vantaggio di mantenere il AddresseeIdpunto dati nella sua colonna riservata e tipizzata correttamente è che facilita notevolmente l'estensione della struttura del database, come illustrerò di seguito.

Progressione dello scenario: integrazione del concetto di status di amicizia

Poiché Friendships può evolversi nel tempo, potresti dover tenere traccia di tale fenomeno, quindi dovresti (i) espandere lo schema concettuale e (ii) dichiarare alcune altre tabelle nel layout logico. Quindi, cerchiamo di organizzare le prossime regole aziendali per delineare le nuove incorporazioni:

  • Un'amicizia detiene uno-a-molti FriendshipStatuses
  • Un FriendshipStatus è principalmente identificato dalla combinazione di RequesterId , AddresseeId e SpecifiedDateTime
  • Un utente specifica zero-one-o-many FriendshipStatuses
  • Uno stato classifica zero-one-o-many FriendshipStatuses
  • Uno stato è identificato principalmente dal suo StatusCode
  • Uno stato viene alternativamente identificato dal suo nome

Diagramma IDEF1X esteso

Successivamente, il precedente diagramma IDEF1X può essere esteso al fine di includere i nuovi tipi di entità e i tipi di interrelazione sopra descritti. Un diagramma che raffigura gli elementi precedenti associati a quelli nuovi è presentato in Figura 2 :

Figura 2. Diagramma IDEF1X dello stato dell'amicizia

Aggiunte di strutture logiche

Successivamente, possiamo allungare il layout DDL con le seguenti dichiarazioni:

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

Di conseguenza, ogni volta che lo stato di una determinata amicizia deve essere aggiornato, gli utenti devono solo INSERIRE una nuova FriendshipStatusriga, contenente:

  • l'idoneo RequesterIde i AddresseeIdvalori — presi dalla Friendshipriga relativa— ;

  • il nuovo e significativo StatusCodevalore - tratto da MyStatus.StatusCode-;

  • l'esatto istante di INSERTion, ovvero —preferibilmente SpecifiedDateTimeusando una funzione server in modo da poterlo recuperare e conservare in modo affidabile—; e

  • il SpecifierIdvalore che indicherebbe il rispettivo UserIdche ha inserito il nuovo FriendshipStatusnel sistema —dealmente, con l'aiuto delle strutture delle tue app —.

In tal senso, supponiamo che la MyStatustabella includa i seguenti dati —con valori PK che sono (a) utenti finali, programmatori di app e DBA-friendly e (b) piccoli e veloci in termini di byte a livello di implementazione fisica -:

 + ------------ + ----------- +
 | StatusCode | Nome       |
 + ------------ + ----------- +
 | R | Richiesto |
 + ------------ + ----------- +
 | A | Accettato |
 + ------------ + ----------- +
 | D | Rifiutato |
 + ------------ + ----------- +
 | B | Bloqued |
 + ------------ + ----------- +

Pertanto, la FriendshipStatustabella può contenere dati come mostrato di seguito:

 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +
 | 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 |
 + ------------- + ------------- + --------------------- ---- + ------------ + ------------- +

Come puoi vedere, si può dire che la FriendshipStatustabella ha lo scopo di comprendere una serie temporale .


Post pertinenti

Potresti anche essere interessato a:

  • Questa risposta in cui suggerisco un metodo di base per affrontare una relazione molti-a-molti comune tra due diversi tipi di entità.
  • Il diagramma IDEF1X mostrato nella Figura 1 che illustra questa altra risposta . Presta particolare attenzione ai tipi di entità denominati Matrimonio e Progenia , perché sono altri due esempi di come gestire il "Problema di esplosione delle parti".
  • Questo post presenta una breve deliberazione sul possesso di diverse informazioni all'interno di una singola colonna.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.