Kleine Code-Fragmente zur Performance-Analyse bei PHP

Benötigte Zeit, Arbeitsspeicher und DB-Zugriffe

Bei meinem CMS-Projekt aestas2 möchte ich – so weit mir mit meinem aktuellen Wissens­stand möglich – alles ordentlich erledigen und richtig machen. Features sind nicht alles, dazu gehört auch Optimierung. Dafür braucht man wiederum Zahlenwerte, die man für Vorher und Nachher vergleichen kann.

Zeitmessung

Am Einstiegspunkt des Skriptes merkt man sich den jetzigen Timestamp. Dann folgt der ganze eigentliche Ablauf mit Datenbankanfragen, Berrechnungen, Ausgaben oder was sonst geschieht. Danach, am Skriptende, wird die benötigte Zeit errechnet und ausgegeben.

$time_start = microtime( true );

[…]

$time_end = microtime( true );
$time = round( $time_end - $time_start, 4 );
echo 'Benötigte Zeit: ' . $time;

Die Messergebnisse schwanken dabei natürlich ein wenig und man sollte die Seite mehrmals neuladen, bevor man das Resultat bewertet. Beim lokalen Entwickeln ist auch zu bedenken, dass jedes weitere laufende Programm wie z.B. der Audioplayer Leistung nimmt und dadurch das Ergebnis verfälscht.

Arbeitsspeicherverbrauch

Das ist eine einfache Sache, denn die Funktionen dafür werden direkt von PHP bereitgestellt mit memory_get_usage() und memory_get_peak_usage().

// Werte gleich in MB umgerrechnet
$mem = round( memory_get_usage() / 1024 / 1024, 2 );
$mem_peak = round( memory_get_peak_usage() / 1024 / 1024, 2 );

Arbeitsspeicher wird belegt für jede inkludierte Datei und jede belegte Variable. Umgekehrt wird Speicher wieder frei, wenn man Variablen löscht mit unset().

Datenbankzugriffe

Hierfür kenne ich soweit nur ein recht ineffizientes Vorgehen, vielleicht hat da jemand einen Tipp, wie es besser geht. Aktuell gehe ich einfach so vor, dass ich nach jedem DB-Query eine globale Zählvariable hochsetze.

$GLOBALS['QUERIES'] = 0;
[…]
function getUsernameForId( $id ) {
	$value = mysql_fetch_object(
		mysql_query( '
			SELECT user_name
			FROM meineTabelle
			WHERE user_id = ' . $id
		)
	);
	$GLOBALS['QUERIES']++;
	return $value;
}
[…]
echo 'DB-Anfragen: ' . $GLOBALS['QUERIES'];

Hinweis: Die Variable $id sollte vorher darauf überprüft werden, ob sie auch eine Zahl ist beziehungsweise Variablen vor dem Verwenden im MySQL-String mit mysql_real_escape_string() behandelt werden.

Die Datenbankzugriffe möglichst gering zu halten, durchaus auch auf Kosten des Arbeits­speichers, lohnt sich sehr für die benötigte Zeit. Ein Blog-Beispiel dafür wäre, dass man alle Einträge für die Seite auf einmal aus der DB holt, anstatt jeden Eintrag einzeln anzufragen.