Sie sind hier : sebastian1012.bplaced.net/ homepage-neu / kreuz-und-quer / tutorials-info-neuigkeiten-php / nachtest-zu-gepufferten-und-ungepufferten-sql-abfragen.php

Nachtest zu gepufferten und ungepufferten SQL-Abfragen

Aufgrund eines fatalen Denkfehlers im letzten Beitrag schiebe ich hier nochmal einen korrigierenden Nachtest nach. Es geht wieder um gepuffertes vs. ungepuffertes Ausführen von SQL-Querys.

Das letzte Mal hab ich eine völlig ungeeignete Abfrage verwendet:

  1. Sie war zu schnell für einen Vergleich bzw. eine eindeutige Entscheidung, ob mysql_unbuffered_query() Sinn macht
  2. Sie enthielt ein ORDER BY, was nicht clever ist, denn MySQL weiß ja auch erst nach Behandlung aller Datensätze, welcher der größte bzw. kleinste Wert ist.

Außerdem habe ich beim letzten Mal lediglich die Gesamtausführungszeit gemessen, was auch sinnfrei war.

Jedenfalls hab ich diesmal eine wesentlich komplexere Abfrage verwendet. Mangels ordentlicher Testdatenbank, mit der ich lange dauernde Querys erzeugen kann (habs einfach nicht gebacken bekommen, eine Abfrage zu schreiben, die 1 – 5 Sekunden dauert – entweder wars im Zehntelsekunden-Bereich oder im Minutenbereich) habe ich folgende, völlig sinnfreie Abfrage verwendet.

SELECT *  FROM `tabelle` a1  INNER JOIN tabelle a2 ON a1.ID=a2.ID  INNER JOIN kategorien ON a1.kategorien_ID=kategorien.ID  WHERE RAND()>0.5 AND RAND()<0.5 AND RAND()>0.5 AND RAND()<0.5 AND RAND()>0.5 AND RAND()<0.5 AND RAND()>0.5 AND RAND()<0.5 AND RAND()>0.5 AND RAND()<0.5 AND RAND()>0.5

Mir war es wichtig, eine Anfrage zu wählen, die so beschaffen ist, dass die Prüfung eines einzlenen Datensatzes genügt, um zu bestimmen, ob er zum Result-Set gehört oder nicht. Dies wäre mit ORDER BY oder GROUP BY nicht möglich.
Die eigentliche Abfrage ist aber völlig egal, denn ihr habt bestimmt auch „richtige“ Abfragen, die einige Sekunden dauern. Grundsätzlich sei an dieser Stelle schon mal gesagt: Je länger eine Abfrage dauert (Gesamtzeit laut PHPMyAdmin), desto sinnvoller ist der Einsatz von mysql_unbuffered_query().

Jedenfalls habe ich mit obiger Query die gepufferte Abfrage-Variante getestet, also mysql_query(). Dabei kam ich auf folgendes Ergebnis:
Zeit bis zur Verarbeitung des ersten Datensatzes: 5.005784034729 s
Zeit bis zur verarbeitung aller Datensätze: 5.0073800086975 s

mysql_unbuffered_query() im Gegenzug kommt auf dieses Ergebnis:
Zeit bis zur Verarbeitung des ersten Datensatzes: 0.24099016189575 s
Zeit bis zur verarbeitung aller Datensätze: 5.2411839962006 s

Leider konnte ich für diesen Test nicht mein Benchmark-Script nutzen, da ich damit ja nur die Gesamtbearbeitungszeit (basierend auf den Ergebnissen des Apache Benchmark-Tools ab.exe) herausbekomme. Das ist auch der Grund, warum es diesmal keine hübsche, bunte Tabelle gibt – ich hoffe die blanken Zahlen reichen diesmal.

Nun also zur Auswertung:
Der Unterschied in der Gesamtzeit ist irrelevant, weil ich wie gesagt nur per microtime() messen konnte. Die Aussage, dass die ungepufferte Version grundsätzlich langsamer sei, würde ich so nicht unterschrieben wollen.
Viel interessanter ist aber der riesige Unterschied bis zur Bearbeitung des ersten Datensatzes. Und genau das ist ja das Ziel von mysql_unbuffered_query(), wie ich dank Tims Kommentar nun auch begriffen habe ;-). Das bedeutet, dass die Bearbeitung durch PHP bereits sehr viel früher beginnen kann.

Also funktionierts doch hervorragend. Eines muss allerdings gesagt werden: mysql_unbuffered_query() macht keinen Sinn bei Querys mit ORDER BY, da sind die Ausführungszeiten zwischen mysql_query() und mysql_unbuffered_query() gleich (Grund: MySQL scheint Quicksort zu verwenden. Mit Heapsort wäre ein Geschwindigkeitsunterschied durchaus möglich).
Außerdem möchte ich noch sagen, dass ungepufferte SQL-Behandlung auch nur sinnvoll ist, wenn die Verarbeitung des Datensatzes schneller geht als die Ermittlung des nachfolgenden im Result-Set. Ansonsten muss MySQL zwangsläufig puffern, weil die Anwendung nicht hinterherkommt.

Außerdem ist wichtig, dass die Wirkung des schnelleren Ausgebens durch PHP verpufft (zumindest merkt der Client davon nix), wenn ihr die Ausgabe durch PHP puffert (z.B. um den Output zu gzippen). Deshalb ists für mich wohl uninteressant, aber ich wollte euch trotzdem die Möglichkeit aufzeigen, die MySQL und PHP da bieten.

Falls Rechtschreibfehler in diesem Beitrag entdeckt werden, bitte ich dies zu entschuldigen. Ich wollte den Test und den Bericht möglichst schnell veröffentlichen, damit ihr nicht von dem vorigen Beitrag verstimmt werdet.