Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie implementiert man ein Tagging-System ähnlich SO in PHP/Mysql?

Bevor wir zur vorzeitigen Optimierung übergehen Modus, kann es hilfreich sein, sich die folgende Abfragevorlage anzusehen. Nicht zuletzt könnte dies als Grundlage dienen, an der die Effektivität möglicher Optimierungen gemessen werden kann.

SELECT T.Tagid, TagInfo.TagName,  COUNT(*)
FROM Items I
JOIN Tags TagInfo ON TagInfo.TagId = T.TagId
JOIN ItemTagMap T  ON I.ItemId = T.ItemId 
--JOIN ItemTagMap T1 ON I.ItemId = T1.ItemId
WHERE I.ItemId IN
  (
      SELECT ItemId 
      FROM Items
      WHERE   -- Some typical initial search criteria
         Title LIKE 'Bug Report%'   -- Or some fulltext filter instead...
         AND  ItemDate > '02/22/2008'
         AND  Status = 'C'
  )
--AND T1.TagId = 'MySql'
GROUP BY T.TagId, TagInfo.TagName
ORDER BY COUNT(*) DESC

Die Unterabfrage ist die "treibende Abfrage", d. h. diejenige, die den anfänglichen Kriterien des Endbenutzers entspricht. (Einzelheiten dazu, wie diese mehrfach erforderliche Abfrage in einen insgesamt optimierten Ablauf passt, finden Sie weiter unten.) Kommentiert ist der JOIN auf T1 (und möglicherweise T2, T3, wenn mehrere Tags ausgewählt sind) und mit der WHERE-Klausel der zugehörige Kriterien. Diese werden benötigt, wenn der Benutzer ein bestimmtes Tag auswählt, sei es als Teil der anfänglichen Suche oder durch Verfeinerung. (Es kann effizienter sein, diese Joins und Where-Klauseln innerhalb der Unterabfrage zu platzieren; mehr dazu weiter unten)

Diskussion... Die "treibende Abfrage" oder eine Variation davon wird für zwei unterschiedliche Zwecke benötigt:

  • 1, um das vollständige bereitzustellen Liste der ItemId, die benötigt wird, um alle zugehörigen Tags aufzuzählen.

  • 2 zum Bereitstellen der ersten N ItemId-Werte (N steht für die Größe der angezeigten Seite), um Artikeldetailinformationen in der Artikeltabelle nachzuschlagen.

Beachten Sie, dass die vollständige Liste nicht sortiert werden muss (oder von einer Sortierung in einer anderen Reihenfolge profitieren kann), wobei die zweite Liste basierend auf der Auswahl des Benutzers sortiert werden muss (z. B. nach Datum, absteigend oder nach Titel, alphabetisch aufsteigend). ). Beachten Sie auch, dass, wenn eine Sortierreihenfolge erforderlich ist, die Kosten der Abfrage den Umgang mit der vollständigen Liste implizieren (abgesehen von einer seltsamen Optimierung durch SQL selbst und/oder einer gewissen Denormalisierung muss SQL die letzten Datensätze auf dieser Liste "sehen") , falls sie sortiert nach oben gehören).

Diese letztere Tatsache spricht dafür, für beide Zwecke dieselbe Abfrage zu haben, die entsprechende Liste kann in einer temporären Tabelle gespeichert werden. Der allgemeine Ablauf wäre, die obersten N Artikeldatensätze mit ihren Details schnell nachzuschlagen und diese sofort an die Anwendung zurückzugeben. Die Anwendung kann dann ajax-modisch die Liste der Tags für Verfeinerungen abrufen. Diese Liste würde mit einer Abfrage ähnlich der obigen erstellt, bei der die Unterabfrage durch "select * from temporalTable" ersetzt wird. Die Chancen stehen gut, dass der SQL-Optimierer entscheidet, diese Liste zu sortieren (in einigen Fällen), lassen wir ihn das tun, anstatt es zu erraten und explizit zu sortieren.

Ein weiterer zu berücksichtigender Punkt besteht darin, die Verknüpfung(en) in der ItemTagMap-Tabelle möglicherweise in die "treibende Abfrage" zu bringen, anstatt wie oben gezeigt. Es ist wahrscheinlich am besten, dies zu tun, sowohl wegen der Leistung als auch weil es die richtige Liste für den Zweck Nr. 2 (Anzeige einer Seite mit Elementen) erzeugt.

Die oben beschriebene Abfrage/der oben beschriebene Ablauf lässt sich wahrscheinlich ziemlich gut skalieren, selbst auf relativ bescheidener Hardware; vorläufig in die 1/2 Million+ Items, mit anhaltenden Benutzersuchen vielleicht bis zu 10 pro Sekunde. Einer der Schlüsselfaktoren wäre die Selektivität der anfänglichen Suchkriterien.

Optimierungsideen

  • [Abhängig von den typischen Suchfällen und den Datenstatistiken] kann es sinnvoll sein, zu denormalisieren, indem einige der Items-Felder in die ItemTagMap-Tabelle gebracht (tatsächlich dupliziert) werden. Gerade kurze Felder können dort 'willkommen' sein.
  • Während die Daten in die Millionen+ Elemente wachsen, könnten wir die typischerweise starke Korrelation einiger Tags (z. B.:in SO kommt PHP oft mit MySql, übrigens oft ohne triftigen Grund...) mit verschiedenen Tricks ausnutzen. Beispielsweise könnte die Einführung von "Multi-Tag"-TagIds die Eingabelogik etwas komplizierter machen, aber auch die Kartengröße erheblich reduzieren.


-- 'genug gesagt! --
Angemessene Architektur und Optimierungen sollten im Lichte der tatsächlichen Anforderungen und des effektiven statistischen Datenprofils ausgewählt werden...