How-To: SQL-Queries cachen (Teil 1: Dateisystem)

7. September 2007 – 17:56

Viele Webanwendungen lesen heutzutage ihre Daten aus Datenbanken. Die mag bequem sein und hat auch einige Vorteile, jedoch auch einen Nachteil: es kann sehr langsam sein.
Oft werden auch Daten bei jedem Abruf neu aus der Datenbank geholt, obwohl es total unnötig ist, z.B. wenn das Ergebnis immer das gleiche ist.

In diesem Fall kann man mit Caching viel Zeit sparen. In diesem Fall werden die Datei im Dateisystem (dieser Artikel) oder im Arbeitsspeicher (ein anderes mal erklärt) zwischengespeichert. Der Vorteil: Die Daten liegen fertig bereit und müssen nur noch ausgelesen werden.

Meine Beispiele beziehen sich alle auf MySQL, der Unterschied zu anderen Datenbankservern besteht nur in den Namen der Befehlen. ;)

Zuerst einmal müssen wir überlegen, welches Format die Daten haben und wie wir es am Besten speichern können. Ich denke, am Häufigsten werden Daten mit mysql_fetch_assoc() aus der Datenbank geholt.

// Eine Abfrage an die Datenbank machen
$sql = "SELECT * FROM tabelle";
$result = mysql_query($sql) or die('Fehler in der SQL Abfrage: '.mysql_error());
 
// ... und das Ergebnis in ein Array schreiben
while ( $row = mysql_fetch_assoc($result) )
{
	$table[] = $row;
}
 
// Ausgabe des Ergebnis Arrays
print_r($table);

In diesem Fall haben wir ein Array. Diese lassen sich mit var_export() und ein bisschen Anhang in eine PHP-Datei schreiben, die sich includieren lässt, was sehr flott ist.

// Schreiben wir die Ausgabe in eine Datei
$file = dirname(__FILE__) . '/table_cache.php'; // Der Dateiname
// Inhalt der Datei zusammenbauen
$content = "<?php\n". // PHP Parser soll hier anfangen
   "/* Abfrage: {$sql} */\n". // Damit man später noch weis, was drin ist
   "\$table = ". var_export($table, true). ";\n". // Nun schreiben wir den Inhalt
   "?".">"; // Ende der Datei
// Datei schreiben
file_put_contents($file, $content);

Die Datei table_cache.php könnte jetzt z.B. so aussehen (PHP Marker wegen Wordpress entfernt):

/* Abfrage: SELECT * FROM tabelle */
$table = array (
  0 => 
  array (
    'Name' => 'foo',
    'Wert' => 'bar',
  ),
  1 => 
  array (
    'Name' => 'Caching',
    'Wert' => 'true',
  ),
);

Wir haben nun einen Cache, aber bei jedem Aufruf des Skriptes wird immernoch jedes Mal die Datenbank gefragt. Dieses wollten wir aber verhindern. So geht’s:

$path = dirname(__FILE__);
if ( file_exists($path . '/table_cache.php') )
{
   include $path . '/table_cache.php';
}
else
{
	// Datenbank auslesen und Cache schreiben
}

Nun gut, aber jetzt werden die Daten für ewig im Cache gehalten. Manchmal kann es aber sinnvoll sein, wenn der Cache z.B. nach einer Stunde verfallen soll. Dazu müssen wir die Routine ein kleines bisschen modifizieren. Mit filemtime() können wir ermitteln, wann eine Datei zum letzte Mal verändert wurde. Wenn der Zeitpunkt der Änderung länger als eine Stunde zurück liegt(Aktuelle Zeit - 3600 Sekunden), dann soll der Cache ignoriert werden:

$file = dirname(__FILE__) . '/table_cache.php'; 
// Wenn Datei vorhanden und Änderungszeit + 1 Stunde in der Vergangenheit
if ( file_exists($file) && filemtime($file) + 3600 > time() )
{
   include $path . '/table_cache.php';
}
else
{
	// Datenbank auslesen und Cache schreiben
}

Das ganze könnte man noch in eine Funktion (wie diese) packen und fertig ist das Caching :)

Feedback und Ideen sind Willkommen, im nächsten Artikel beschreib ich das Verfahren mit memcache :)

Kommentar schreiben