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

Optimierung der MySQL-Abfrage (Vorlieben/Abneigungen)

In Bezug auf die Leistung können diese korrelierten Unterabfragen Ihr Mittagessen fressen. Und verschlingen Sie auch Ihre Lunchbox für große Sets, wegen der Art und Weise, wie MySQL sie verarbeitet. Jede dieser Unterabfragen wird für jede Zeile ausgeführt, die in der äußeren Abfrage zurückgegeben wird. Und das kann bei großen Sets sehr teuer werden.

Ein alternativer Ansatz besteht darin, eine Inline-Ansicht zu verwenden, um die Vorlieben und Abneigungen für alle Inhalte zu materialisieren und dann eine Join-Operation durchzuführen.

Dieser Ansatz kann jedoch auch teuer sein, insbesondere wenn Sie nur die „Zählungen“ der Stimmen für nur wenige Inhaltszeilen von einer Bazillion Zeilen benötigen. Häufig gibt es ein Prädikat aus der äußeren Abfrage, das auch in die Inline-Ansicht integriert werden kann, um die Anzahl der Zeilen zu begrenzen, die untersucht und zurückgegeben werden müssen.

Wir möchten einen OUTER-Join für diese Inline-Ansicht verwenden, sodass ein Ergebnis zurückgegeben wird, das Ihrer Abfrage entspricht. Rückgabe einer Zeile aus content wenn es keine übereinstimmenden Zeilen in vote gibt Tabelle.

SELECT [... BUNCH OF FIELDS ...]
     , COALESCE(v.likes,0) AS likes
     , COALESCE(v.dislikes,0) AS dislikes
     , COALESCE(v.myvote,'.Constants::NO_VOTE.') AS myvote
  FROM content c
  LEFT
  JOIN ( SELECT vt.cId
              , SUM(vt.vote = '.Constants::LIKE.') AS likes
              , SUM(vt.vote = '.Constants::DISLIKE.') AS dislikes
              , MAX(IF(vt.userId = '.USER_ID.',vt.vote,NULL)) AS myvote
           FROM votes vt
          GROUP
             BY vt.cId
       ) v
    ON v.cId = c.contentId

       [... OTHER STUFF ... ]

Beachten Sie, dass die Inline-Ansichtsabfrage (mit dem Alias ​​v ) wird sich JEDE einzelne Zeile der votes ansehen Tisch. Wenn Sie nur eine Teilmenge benötigen, sollten Sie erwägen, ein geeignetes Prädikat hinzuzufügen (entweder in einer WHERE-Klausel oder als JOIN zu einer anderen Tabelle). Es gibt keinen Hinweis von [... OTHER STUFF ...] in Ihrer Abfrage, ob nur ein paar Zeilen von content zurückgegeben werden oder wenn Sie alle Zeilen benötigen, weil Sie nach likes ordnen usw.

Für eine kleine Anzahl von Zeilen, die aus dem content ausgewählt wurden Tabelle kann die Verwendung der korrelierten Unterabfragen (wie in Ihrer Abfrage) tatsächlich schneller sein, als eine riesige Inline-Ansicht zu materialisieren und eine Join-Operation dafür durchzuführen.

Ach... und bei beiden Abfragen versteht es sich von selbst, dass ein entsprechender Index auf den votes Tabelle mit einer führenden Spalte von cId kommt der Leistung zugute. Für die Inline-Ansicht möchten Sie nicht, dass MySQL einen filesort durchführen muss Operation für alle diese Zeilen, um die GROUP BY durchzuführen. Und für die korrelierten Unterabfragen möchten Sie, dass sie einen Indexbereichsscan verwenden, keinen vollständigen Scan.