Question

Si A est un ami de B, puis-je conserver les valeurs AB et BA, ou un seul suffit? Quels sont les avantages et les inconvénients des deux méthodes.

Voici mon observation:

  • Si je continue à la fois je dois mettre à jour à la fois lors de recevoir une demande d'un ami.
  • Si je ne garde pas les deux, alors je l'ai trouvé difficile quand avoir à faire plusieurs JOIN avec ce tableau.

À l'heure actuelle, je continue à la manière d'une relation.

entrer image description ici

Alors, que dois-je faire dans ce cas? Un conseil?

Était-ce utile?

La solution

Je stocker AB et BA. Une amitié est vraiment une relation à double sens, chaque entité est liée à une autre. Même si intuitivement nous pensons à la « amitié » comme un lien entre deux personnes, d'un point de vue relationnel, il est plus comme « A a un ami B » et « B a un ami A ». Deux relations, deux dossiers.

Autres conseils

Si l'amitié est destinée à être symétrique (il est impossible pour A être amis avec B mais pas vice-versa), alors je voudrais simplement stocker la relation à sens unique avec une contrainte de vérification assurant que chaque relation ne peut être représenté dans un sens.

Aussi je fossé l'ID de remplacement et un composite PK à la place (et peut-être un indice composite unique, également sur les colonnes renversées).

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

Vous ne dites pas les requêtes que cela rend difficile, mais vous pouvez toujours créer une vue

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

En supposant une « amitié » est toujours dans les deux sens / mutuelle, je serais probablement débrouille quelque chose comme ça.

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

Le résultat est que vous changiez d'un grand nombre à plusieurs rejoindre de « personne » à « personne », à un grand nombre à plusieurs rejoindre de « personne » à « amitié ». Cela simplifiera les jointures et les contraintes, mais a pour effet secondaire de permettre plus de deux personnes dans une seule « amitié » (mais peut-être la flexibilité supplémentaire serait un avantage potentiel).

Vous devrez peut-être définir des index autour des amitiés au lieu de doubler le nombre de lignes:

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

De cette façon, vous doublez le stockage des index, mais pas pour les données de la table. En conséquence, cela devrait être une économie de 25% sur l'espace disque. Le MySQL Query Optimizer choisira effectuer plage d'index analyse uniquement, ce qui explique pourquoi le concept de couvrir les index fonctionne bien ici.

Voici quelques liens sympas sur la couverture des indices:

CAVEAT

Si l'amitié n'est pas réciproque, vous avez la base pour un autre type de relation: FOLLOWER

Si friend_to est pas un ami de friend_of, vous pouvez simplement laisser cette relation hors de la table.

Si vous voulez définir des relations pour tous les types, qu'ils sont réciproques ou non, vous pouvez probablement utiliser la mise en page de tableau suivant:

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

A partir de la table de relation, vous pouvez organiser les relations inclure les éléments suivants:

  • Les amis doivent être réciproque
  • Ennemis pourrait être réciproque ou non
  • Suiveurs pourrait être réciproque ou non
  • Les autres relations serait sujette à interprétation (par l'oubli ou abandonné ou le destinataire de la vengeance (fixe))
  • les relations possibIe peuvent encore être étendues

Cela devrait être plus robuste pour toutes les relations, si la relation est réciproque ou non.

Si vous pouvez contrôler dans l'application que id A est Baissez toujours que id B (pré commande les A, les éléments B ids) vous pouvez tirer parti de demander sans OR (choisir où ID_A = a et ID_B = b, au lieu de demander (ID_A = a et ID_B = b) OU (ID_A = b = eT ID_B a)), et aussi de maintenir la moitié des dossiers dont vous aurez besoin avec les autres approximations de pour. Ensuite, vous devez utiliser un autre champ pour maintenir l'état de la relation (sont-amis, un à-b sollicité, b-sollicité à un, exfriends-a, exfriends-b), et vous avez terminé.

Ceci est la façon dont j'ai réussi mon système d'amitié, ce qui simplifie le système et utilise la moitié des lignes que vous aurez besoin avec d'autres systèmes, que dire A est égale à la valeur id inférieure dans le code.

Licencié sous: CC-BY-SA avec attribution
Non affilié à dba.stackexchange
scroll top