it-swarm-eu.dev

Jak mám navrhnout vztahový vztah pro přátelství?

Pokud je A přítelem B, měl bych si uložit obě hodnoty AB a BA, nebo jedna stačí? Jaké jsou výhody a nevýhody obou metod.

Zde je moje pozorování:

  • Pokud si ponechám obojí, musím aktualizovat oba, když dostanu žádost od přítele.
  • Pokud neudržím oba, zjistil jsem, že je obtížné, když musím s touto tabulkou udělat více JOIN.

V současné době udržuji vztah jednosměrně.

enter image description here

Co bych tedy měl udělat v tomto případě? Nějaká rada?

34
Chan

Uložil bych AB a BA. Přátelství je opravdu obousměrný vztah, každá entita je spojena s jinou. I když intuitivně považujeme „přátelství“ za jedno spojení mezi dvěma lidmi, z relačního hlediska je to spíše jako „A má přítele B“ a „B má přítele A“. Dva vztahy, dva záznamy.

30
datagod

Pokud má být přátelství symetrické (tj. Není možné, aby A bylo přáteli s B, ale ne naopak), pak bych jen uložil jednosměrný vztah s kontrolou omezení že každý vztah může být reprezentován pouze jedním způsobem.

Také bych příkopem náhradní id a místo toho mít kompozitní PK (a možná i složený jedinečný index také na obrácených sloupcích).

CREATE TABLE Friends
  (
     UserID1 INT NOT NULL REFERENCES Users(UserID),
     UserID2 INT NOT NULL REFERENCES Users(UserID),
     CONSTRAINT CheckOneWay CHECK (UserID1 < UserID2),
     CONSTRAINT PK_Friends_UserID1_UserID2 PRIMARY KEY (UserID1, UserID2),
     CONSTRAINT UQ_Friends_UserID2_UserID1 UNIQUE (UserID2, UserID1)
  ) 

Nehovoříte dotazy, které to ztěžují, ale vždy můžete vytvořit pohled

CREATE VIEW Foo
AS
SELECT UserID1,UserID2 
FROM Friends
UNION ALL
SELECT UserID2,UserID1 
FROM Friends
13
Martin Smith

Za předpokladu, že „přátelství“ je vždy obousměrné/vzájemné, asi bych s tím něco takového zvládl.

CREATE TABLE person (
    person_id int IDENTITY(1,1) PRIMARY KEY,
    ...other columns...
)

CREATE TABLE friendship (
    friendship_id int IDENTITY(1,1) PRIMARY KEY,
    ...other columns, if any...
)

CREATE TABLE person_friendship (
    person_id int NOT NULL,
    friendship_id int NOT NULL
    PRIMARY KEY (person_id, friendship_id)
)

Výsledkem je, že jej změníte z spojování mnoha osob z „osoby“ na „osobu“, na spojení mnoha osob z „osoby“ na „přátelství“. Tím se zjednoduší spojení a omezení, ale to má vedlejší účinek, protože umožňuje více než dvěma lidem v jednom „přátelství“ (i když možná další flexibilita by byla potenciální výhodou).

7
db2

Možná budete muset definovat indexy kolem přátelství namísto zdvojnásobení počtu řádků:

CREATE TABLE person
(
    person_id INT NOT NULL AUTO_INCREMENT,
    ...
    PRIMARY KEY (person_id)
);
CREATE TABLE friendship
(
    friend_of INT NOT NULL,
    friend_to INT NOT NULL,
    PRIMARY KEY (friend_of,friend_to),
    UNIQUE KEY friend_to (friend_to,friend_of)
);

Tímto způsobem zdvojnásobíte úložiště pro indexy, ale ne pro data tabulky. Výsledkem by měla být úspora 25% místa na disku. Optimalizátor dotazů MySQL vybere pouze provedení skenování rozsahu indexů, a proto zde dobře funguje koncept pokrytí indexů.

Zde je několik pěkných odkazů na krycí indexy:

CAVEAT

Pokud přátelství není vzájemné, máte základ pro jiný typ vztahu: FOLLOWER

Pokud friend_to není přítelem friend_of, můžete tento vztah jednoduše vynechat z tabulky.

Pokud chcete definovat vztahy pro všechny typy, ať už jsou vzájemné nebo ne, pravděpodobně byste mohli použít následující rozvržení tabulky:

CREATE TABLE person
(
    person_id INT NOT NULL AUTO_INCREMENT,
    ...
    PRIMARY KEY (person_id)
);
CREATE TABLE relationship
(
    rel_id INT NOT NULL AUTO_INCREMENT,
    person_id1 INT NOT NULL,
    person_id2 INT NOT NULL,
    reltype_id TINYINT,
    PRIMARY KEY (rel_id),
    UNIQUE KEY outer_affinity (reltype_id,person_id1,person_id2),
    UNIQUE KEY inner_affinity (reltype_id,person_id2,person_id1),
    KEY has_relationship_to (person1_id,reltype_id),
    KEY has_relationship_by (person2_id,reltype_id)
);
CREATE TABLE relation
(
    reltype_id TINYINT NOT NULL AUTO_INCREMENT,
    rel_name VARCHAR(20),
    PRIMARY KEY (reltype_id),
    UNIQUE KEY (rel_name)
);
INSERT INTO relation (relation_name) VALUES
('friend'),('follower'),('foe'),
('forgotabout'),('forsaken'),('fixed');

Z relační tabulky můžete uspořádat vztahy tak, aby obsahovaly následující:

  • Přátelé by měli být vzájemní
  • Nepřátelé by mohli být vzájemní nebo ne
  • Následovníci mohou být vzájemní nebo ne
  • Ostatní vztahy by podléhaly interpretaci (zapomenutým nebo opuštěným nebo příjemcem pomsty (pevná))
  • Možné vztahy lze dále rozšiřovat

To by mělo být robustnější pro všechny vztahy, ať už je vztah vzájemný nebo ne.

4
RolandoMySQLDBA

Pokud můžete v rámci aplikace ovládat, že id A je vždy nižší než id B (před objednáním id prvků A, B prvků), můžete využít dotazování bez OR (vyberte kde id_A = a AND id_B = b, namísto dotazování (id_A = a AND id_B = b) OR (id_A = b AND id_B = a)) a také udržovat polovinu záznamů, které budete potřebovat s aproximacemi ostatních. Pak byste měli použít jiné pole k udržení stavu vztahu (jsou-přátelé, a-vyžádané-k-b, b-vyžádané-k-a, exfriends-a, exfriends-b) a vy je hotovo.

Toto je způsob, jakým jsem spravoval svůj systém přátelství, což zjednodušuje systém a používá polovinu řádků, které budete potřebovat u jiných systémů, pouze říká, že A se rovná nižší hodnotě id v kódu.

1
appartisan