Je développe une relation d'amitié dans MySQL où la relation d'ami est mutuelle. Si A est l'ami de B, alors B est l'ami de A. Si l'un des utilisateurs met fin à l'amitié, la relation tombe. Je veux savoir quelle voie est la meilleure.
J'ai un système en marche;
user
-----------
userid p.k
name
friends
-------
userid
friendid
primary key (`userid`,`friendid`),
key `friendid` (`friendid`)
1 2
2 5
1 3
To get all of my friends;
SELECT u.name, f.friendid , IF(f.userid = $userid, f.friendid, f.userid) friendid
FROM friends f
inner join user u ON ( u.userid = IF(f.userid = $userid, f.friendid, f.userid))
WHERE ( f.userid = '$userid' or f.friendid = '$userid' )
Cette requête fonctionne bien. Je peux peut-être en ajouter un UNION
. La requête est plus compliquée que celle ci-dessous et le tableau contient deux fois moins d'enregistrements que celui ci-dessous.
Une autre façon consiste à conserver les relations sur des lignes distinctes;
1 2
2 1
2 5
5 2
1 3
3 1
SELECT u.name, f.friendid
FROM friends f inner join user u ON ( u.userid = f.friendid )
WHERE f.userid = '$userid'
Cette requête est simple, bien que la table occupe deux fois plus d'espace.
Ma crainte est; en supposant qu'il y a des millions d'utilisateurs; quel chemin fonctionnera plus rapidement?
Quels sont les avantages et les inconvénients des deux façons?
Que dois-je garder à l'esprit ou changer pour ces façons? Et à quels problèmes puis-je faire face dans les deux sens?
la source
Réponses:
La première chose qui attire mon attention est la configuration de l'index
friends
.Vous avez ceci en ce moment:
Lorsque vous recoupez pour une amitié mutuelle, cela peut entraîner de petites dépenses car l'ID utilisateur peut être récupéré de la table lors de la traversée de l'
friendid
index. Vous pourriez peut-être indexer comme suit:Cela peut supprimer tout besoin d'accéder à la table et de rechercher l'index uniquement.
Maintenant, en termes de requêtes, les deux peuvent s'améliorer avec le nouvel index unique. La création de l'index unique élimine également la nécessité d'insérer
(A,B)
et(B,A)
dans la table car(A,B)
et(B,A)
serait l'index de toute façon. Ainsi, la deuxième requête n'aurait pas à parcourir le tableau pour voir si quelqu'un est un ami de quelqu'un d'autre parce qu'une autre personne a initié l'amitié. De cette façon, si l'amitié est rompue par une seule personne, il n'y a pas d'amitié orpheline à sens unique (cela ressemble beaucoup à la vie de nos jours, n'est-ce pas?)Votre première requête semble bénéficier davantage de l'index unique. Même avec des millions de lignes, localiser des amis en utilisant uniquement les index éviterait de toucher la table. Néanmoins, comme vous n'avez pas présenté de requête UNION, je voudrais recommander une requête UNION:
Cela vous permettra de voir qui sont les amis de chaque ID utilisateur
Pour voir toutes les amitiés, lancez ceci:
Tout d'abord, voici quelques exemples de données:
Regardons toutes les relations
Examinons les 5 ID utilisateur et voyons si les relations sont correctement affichées
Ils me semblent tous corrects.
Maintenant, utilisons notre deuxième requête pour voir si elle correspond ...
Pourquoi ne correspond pas? C'est parce que je n'ai pas chargé le
(B,A)
pour tous(A,B)
. Permettez-moi de charger les(B,A)
relations et de réessayer votre deuxième requête.Ils ne correspondent toujours pas. C'est parce que votre deuxième requête ne vérifie qu'un côté.
Vérifions votre première requête par rapport à chaque valeur avec seulement (A, B) et non (B, A):
Votre premier fonctionne bien. Je suis sûr qu'il bénéficie de l'index unique comme je l'ai dit plus tôt, mais à mon humble avis je pense que l'UNION est plus simple. Avec cet index unique, il semblerait qu'il s'agisse de six sur une douzaine et demie de l'autre en termes d'exécution et de sortie.
Vous devrez comparer votre première requête à ma suggestion UNION et voir.
C'était une bonne question que vous avez posée aujourd'hui. +1 pour votre question.
la source
friendid
,userid
) et maintenant les résultats sont à peu près .00794 Est-ce aussi rapide que possible? En regardant les résultats, pensez-vous que la première façon est meilleure (une ligne pour chaque relation)? Parce que c'est deux fois moins d'espace que le second et les résultats sont à peu près les mêmes avec les configurations actuelles.WHERE
,GROUP BY
et lesORDER BY
clauses résultent des données sont lues à partir des index uniquement. Voici quelques bons liens qui justifient l'utilisation des clés uniques et primaires comme index de couverture: 1) peter-zaitsev.livejournal.com/6949.html , 2) mysqlperformanceblog.com/2006/11/23/… , 3) ronaldbradford .com / blog / tag / couverture-index