Ich entwickle eine Freundschaftsbeziehung in MySQL, in der die Freundschaftsbeziehung gegenseitig ist. Wenn A ein Freund von B ist, ist B ein Freund von A. Wenn einer der Benutzer die Freundschaft beendet, wird die Beziehung unterbrochen. Ich möchte lernen, welcher Weg besser ist.
Ich habe ein laufendes System;
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' )
Diese Abfrage funktioniert gut. Vielleicht kann ich eine hinzufügen UNION
. Die Abfrage ist komplizierter als die folgende und die Tabelle enthält halb so viele Datensätze wie die folgende.
Eine andere Möglichkeit besteht darin, die Beziehungen in separaten Zeilen zu halten.
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'
Diese Abfrage ist einfach, obwohl die Tabelle doppelt so viel Speicherplatz benötigt.
Meine Sorge ist; unter der Annahme, dass es Millionen von Benutzern gibt; Welcher Weg wird schneller funktionieren?
Was sind die Vor- und Nachteile beider Wege?
Was muss ich beachten oder auf diese Weise ändern? Und welchen Problemen kann ich in beide Richtungen begegnen?
quelle
Antworten:
Das erste, was mir auffällt, ist das Index-Setup für
friends
.Sie haben dies im Moment:
Bei der Überprüfung auf gegenseitige Freundschaft kann dies zu geringen Kosten führen, da die Benutzer-ID beim Durchlaufen des
friendid
Index möglicherweise aus der Tabelle abgerufen wird . Vielleicht könnten Sie wie folgt indizieren:Dadurch entfällt möglicherweise die Notwendigkeit, auf die Tabelle zuzugreifen und nur den Index zu durchsuchen.
In Bezug auf die Abfragen können sich beide mit dem neuen eindeutigen Index verbessern. Den eindeutigen Index Erstellen entfällt auch die Notwendigkeit einzufügen
(A,B)
und(B,A)
in der Tabelle da(A,B)
und(B,A)
den Index ohnehin wäre. Somit müsste die zweite Abfrage nicht durch die Tabelle blättern, um zu sehen, ob jemand ein Freund von jemand anderem ist, weil eine andere Person die Freundschaft initiiert hat. Auf diese Weise gibt es, wenn die Freundschaft nur von einer Person gebrochen wird, keine verwaisten Freundschaften, die einseitig sind (scheint heutzutage dem Leben sehr ähnlich zu sein, nicht wahr?)Ihre erste Abfrage scheint mehr vom eindeutigen Index zu profitieren. Selbst bei Millionen von Zeilen würde das Auffinden von Freunden, die nur die Indizes verwenden, das Berühren der Tabelle vermeiden. Da Sie jedoch keine UNION-Abfrage vorgelegt haben, möchte ich eine UNION-Abfrage empfehlen:
Auf diese Weise können Sie sehen, wer die Freunde jeder Benutzer-ID sind
Führen Sie Folgendes aus, um alle Freundschaften anzuzeigen:
Hier sind zunächst einige Beispieldaten:
Schauen wir uns alle Beziehungen an
Schauen wir uns alle 5 Benutzer-IDs an und sehen, ob die Beziehungen korrekt angezeigt werden
Sie sehen für mich alle richtig aus.
Lassen Sie uns nun Ihre zweite Abfrage verwenden, um zu sehen, ob sie übereinstimmt ...
Warum nicht zusammenpassen? Das liegt daran, dass ich das nicht
(B,A)
für jeden geladen habe(A,B)
. Lassen Sie mich die(B,A)
Beziehungen laden und Ihre zweite Abfrage erneut versuchen.Sie passen immer noch nicht zusammen. Das liegt daran, dass Ihre zweite Abfrage nur eine Seite überprüft.
Lassen Sie uns Ihre erste Abfrage mit jedem Wert nur mit (A, B) und nicht mit (B, A) vergleichen:
Dein erstes funktioniert gut. Ich bin sicher, dass es von dem einzigartigen Index profitiert, wie ich bereits sagte, aber meiner Meinung nach ist die UNION einfacher. Mit einem eindeutigen Index scheint es in Bezug auf Ausführung und Ausgabe sechs von anderthalb Dutzend der anderen zu sein.
Sie müssten Ihre erste Anfrage mit meinem Vorschlag UNION vergleichen und sehen.
Dies war eine gute Frage, die Sie heute gestellt haben. +1 für deine Frage.
quelle
friendid
,userid
) ersetzt und jetzt sind die Ergebnisse ungefähr .00794. Ist das so schnell wie möglich? Wenn Sie sich die Ergebnisse ansehen, denken Sie, dass der erste Weg besser ist (eine Zeile für jede Beziehung)? Weil es doppelt so wenig Speicherplatz wie das zweite ist und die Ergebnisse mit den aktuellen Setups ungefähr gleich sind.WHERE
,GROUP BY
undORDER BY
Klauseln führen zu Daten nur von Indizes gelesen werden. Hier sind einige gute Links, die die Verwendung der eindeutigen und Primärschlüssel als Indexe rechtfertigen: 1) peter-zaitsev.livejournal.com/6949.html , 2) mysqlperformanceblog.com/2006/11/23/… , 3) ronaldbradford .com / blog / tag / covering-index