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í:
JOIN
.V současné době udržuji vztah jednosměrně.
Co bych tedy měl udělat v tomto případě? Nějaká rada?
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.
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
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).
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í:
To by mělo být robustnější pro všechny vztahy, ať už je vztah vzájemný nebo ne.
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.