Archiv für den Monat: April 2012

Schneller in PHP und MySQL mit JOIN

Mittels einfacher Kentnisse seiner Datenbank kann der Entwickler auch aus Legacy-Anwendungen sehr viel mehr Geschwindigkeit herausholen, als er vielleicht weiß.
Der Grund ist simpel: Meist bleibt der Code gleich, aber die Server Software wird aktualisiert. Während die Erstellung noch im guten alten PHP4 + MySQL4 von Statten ging, rennt der Code heute mit PHP5 + MySQL5 zwar immer noch, könnte aber dank kleiner Kniffe sehr viel schneller sein.
Ich möchte euch einen Weg dazu zeigen, die JOINs in MySQL. Es gibt sicherlich noch mehr Möglichkeiten, aber das sind auch andere Themen. Fangen wir heute mal mit alten Querys an.

Zunächst versuchen wir eine Stelle zu finden, an der wir ansetzen. Bei den meisten Legacy Codes wurde mit solch einem oder einem ähnlichen Konstrukt die Daten für „Zeige neue Blogbeiträge mit Namen des Autors“ abgerufen, wobei „autor“ und „blog“ zwei verschiedene Tabellen sind.

$_res = mysql_query("SELECT * FROM blog ORDER BY datum DESC");
while ($row = mysql_fetch_array($_res)) {

  $_resAutor = mysql_query("SELECT * FROM autor WHERE autorid = ".$row['autorid']);
  $autor = mysql_fetch_array($_resAutor);
  // Stelle Blogbeitrag mit Autor dar
}

Das ist nicht nur in der Hinsicht des Datenabrufes schlechter Code und vor lauter „code-smells“ könnte einem glatt schlecht werden. Trotzdem gibt es sowas „da draussen“ und dummerweise funktioniert das leider immer noch.

Was kann man verbessern? Zum einen fällt auf, dass es zwei Querys sind. Das muss nicht nur nicht sein, dass ist auch noch ganz schlecht, denn jede Verbindung zur Datenbank braucht Zeit und die sollten wir uns sparen. Argumente wie „mysqli / PDO benutzen“ lasse ich ganz bewusst aussen vor, es soll um Prinzip gehen (sicher wäre die Verwendung eines PDO oder ORM wie Doctrine besser, ganz klar).

Sparen wir uns also den zusätzlichen Query:

$_res = mysql_query("SELECT b.*, a.* FROM blog b, autor a WHERE b.autorid = a.autorid ORDER BY b.datum DESC");
while ($row = mysql_fetch_array($_res)) {
  // Stelle Blogbeitrag mit Autor dar
}

Schon viel besser, aber noch nicht gut genug. Was passiert, wenn ein Blogbeitrag existiert, aber der Autor nicht? Bei so einer Legacy-Anwendung fast schon der Normalfall. Der ganze Beitrag fehlt. Doof, also brauchen wir eine Mechanik, die trotz fehlendem Autor den Blog Beitrag noch anzeigt.
Ganz kurz: Das machen JOINs – und ehe ich nun von vielen gesteinigt werde: JOINs machen noch viel mehr, aber das würde hier den Rahmen sprengen und außerdem möchte ich dazu noch mehr schreiben.

Das ganze nun mit einem LEFT JOIN:

$_res = mysql_query("SELECT b.*, a.* FROM blog b LEFT JOIN autor a ON (b.autorid = a.autorid) ORDER BY b.datum DESC");
while ($row = mysql_fetch_array($_res)) {
  // Stelle Blogbeitrag mit Autor dar
}

Es ändert sich nicht viel, aber nun erscheinen auch alle Blogbeiträge ohne Autor und als kleines Extra arbeitet der letzte Query auch noch etwas schneller als der zweite; super für Legacy-Code, der schon ähnlich wie in Beispiel Zwei aufgebaut ist, denn dort muss man nicht – oder nur wenig – an den PHP Code ran und kann sich auf die reine SQL-Optimierung konzentrieren.

Diese Art der Optimierung alter Legacy-Anwendungen macht relativ wenig Arbeit und bringt dafür recht viel. Vor allem im Bereich von SQL-Code, wo Beispiel eins mehrfach vorkommt (Grundquery, dannach werden viele Querys gestartet die Detaildaten zum Grundquery abrufen, dannach wird gerechnet und wieder neue Querys abgerufen usw.) und damit die Anwendung an dieser Stelle nur sehr langsam ist, kann ein Umstieg auf JOINs und u.a. Verlagerung von Arbeit von PHP in den Query sehr viel Geschwindigkeit herausholen.

Allerdings – und das sollte ganz klar sein – kann dies keine schlechte Architektur ersetzen. Legacy Code kommt irgendwann an den Punkt, an dem ein Optimieren keinen Sinn mehr macht und man sich lieber auf die Neukonzeption konzentrieren sollte. Als Hilfsmittel, um z.B. langsame Bereiche zu beschleunigen, sollte man die Kentnisse allerdings auffrischen. Vor allem, da bei modernen Methoden (PDO, OML, …) die JOINs eine zentrale Rolle spielen.