PHP Query Cache

PHP Query Cache

am 09.04.2008 10:41:37 von Ulf Seltmann

Hallo Gruppe.

Wir abstrahieren über eine Klasse den Zugriff auf bestimmte Tabellen.
Die Klasse stellt verschiedene Methoden bereit.
Jetzt kommt es vor, dass eine der Methoden im Schleifendurchlauf
aufgerufen wird und immer eine Query mit unterschiedlicher WHERE-Klausel
absetzt. Dabei sind drei viertel der Querys identisch (gleiche
WHERE-Klausel) und ich frage mich, ob es Sinn macht einen
PHP-Query-Cache[1] in die Klasse zu implementieren. Ich würde in diesem
Fall auf Update-Prüfung verzichten, da es unwahrscheinlich ist, dass
sich die Daten während der Laufzeit der Anwendung ändern. Mir stellt
sich eher die Frage, ob es Sinn macht einen PHP-Query-Cache zu
implementieren, wo doch (in meinem Falle) MySQL selbst Query-Cache zur
Verfügung stellt und höchstwahrscheinlich besser implementiert, als ich
das je kann.

Ich bitte um Meinungen und Erfahrungswerte.

ciao

Ulf

[1]würde ungefähr so aussehen:

function getFoo($query) {
static $cache = array();

if (!isset($cache[$query])) {
$cache[$query] = db::getResultSet($query);
}

return $cache[$query];
}

Re: PHP Query Cache

am 09.04.2008 11:08:04 von foo

Ulf Seltmann schrieb:
> Mir stellt
> sich eher die Frage, ob es Sinn macht einen PHP-Query-Cache zu
> implementieren, wo doch (in meinem Falle) MySQL selbst Query-Cache zur
> Verfügung stellt und höchstwahrscheinlich besser implementiert, als ich
> das je kann.

Vorgehen ohne Cache:
1. Sende Query an DB
2. DB überprüft, ob Query bekannt
3. Falls Query bekannt, sende Ergebnis

Vorgehen mit Cache:
1. Überprüfe, ob Ergebnis bekannt ist
2. Nutze das Ergebnis

Mal abgesehen davon, dass die zweite Aufzählung einen Punkt weniger hat:
Lese das Wort *senden*. Du mußt mit der Datenbank kommunizieren - das
braucht Zeit. Das schlichte Nachschlagen im RAM und die sofortige
Nutzung ist erheblich schneller.

Gruß,
Torsten

Re: PHP Query Cache

am 09.04.2008 12:10:26 von steffen bruentjen

Ulf Seltmann wrote:
>Hallo Gruppe.
>
>Wir abstrahieren über eine Klasse den Zugriff auf bestimmte Tabellen.
>Die Klasse stellt verschiedene Methoden bereit.
>Jetzt kommt es vor, dass eine der Methoden im Schleifendurchlauf
>aufgerufen wird und immer eine Query mit unterschiedlicher WHERE-Klausel
>absetzt. Dabei sind drei viertel der Querys identisch (gleiche
>WHERE-Klausel) und ich frage mich, ob es Sinn macht einen
>PHP-Query-Cache[1] in die Klasse zu implementieren. Ich würde in diesem
>Fall auf Update-Prüfung verzichten, da es unwahrscheinlich ist, dass
>sich die Daten während der Laufzeit der Anwendung ändern. Mir stellt
>sich eher die Frage, ob es Sinn macht einen PHP-Query-Cache zu
>implementieren, wo doch (in meinem Falle) MySQL selbst Query-Cache zur
>Verfügung stellt und höchstwahrscheinlich besser implementiert, als ich
>das je kann.

Nicht nur das. Der Query-Cache von MySQL ist vor allem serverseitig.
Aber der Reihe nach... Zunächst mal kannst Du Dir die Werte des
Query-Caches von MySQL mit diesen Statements anschauen:

SHOW VARIABLES LIKE 'have_query_cache';
SHOW VARIABLES LIKE 'query_cache%';
SHOW STATUS LIKE 'Qcache%';

Serverseitig vorbereitete Statements (z.B. PDO) werden nicht im
Query-Cache von MySQL abgelegt. Das sollte sich offensichtlich mal
ändern; Auf http://www.golem.de/0610/48593.html wird von einer PHP-API
geschrieben, welche einen clientseitigen Query-Cache unterstützt. Ob
das noch aktuell ist, ist nicht so wichtig, weil ein clientseitiger
Query-Cache nicht so richtig viel bringt. Auch bei Deiner Idee würde
eine identische Query pro Nutzer und pro Seitenaufruf 1x ausgeführt
werden.

Wenn Du also den serverseitigen Query-Cache von MySQL verwenden
willst, musst Du clientseitige prepared statements (und damit nicht
PDOs prepare()) oder Methoden wie mysqli_real_escape_string()
benutzen.

Wenn Dir ein clientseitiger Query-Cache ausreicht, kannst Du ihn so
wie beschrieben implementieren. Alternativ kannst Du auch Objekte
anlegen, welche nur 1x pro Verbindung mit den Werten der Datenbank
initialisiert werden - auf diese Weise müsste die Query nicht
identisch sein.

Die sinnvollste Lösung lässt sich nur schwer beschreiben, denn es
hängt immer von Menge und Organisation der Daten in der Datenbank und
von Deinen Queries ab.

Schöne Grüße, Steffen

--
Das Tastaturlayout für Programmierer:
http://eurkey.steffen.bruentjen.eu

Re: PHP Query Cache

am 09.04.2008 17:19:23 von Ulf Seltmann

steffen bruentjen schrieb:
> Wenn Du also den serverseitigen Query-Cache von MySQL verwenden
> willst, musst Du clientseitige prepared statements (und damit nicht
> PDOs prepare()) oder Methoden wie mysqli_real_escape_string()
> benutzen.
>
> Wenn Dir ein clientseitiger Query-Cache ausreicht, kannst Du ihn so
> wie beschrieben implementieren. Alternativ kannst Du auch Objekte
> anlegen, welche nur 1x pro Verbindung mit den Werten der Datenbank
> initialisiert werden - auf diese Weise müsste die Query nicht
> identisch sein.
>
> Die sinnvollste Lösung lässt sich nur schwer beschreiben, denn es
> hängt immer von Menge und Organisation der Daten in der Datenbank und
> von Deinen Queries ab.

Ich habe mal ein paar Lasttests gemacht und musste feststellen, dass die
Anwendung mit PHP-Query-Cache (60 x mysql_query) nicht schneller ist,
als nur mit MySQL-Query-Cache (1500 x mysql_query). Einzig die
Lastverteilung auf die Datenkank macht mir Sorge. Und das wirkt sich ja
produktiv anders aus, als auf meinem Testsystem (wo ich als einziger
zugreife).
Ich neige stark dazu die Performance-Optimierung an den Admin abzugeben :)

Ein hilfreicher Text neben den hier geposteten Kommentaren war übrigens [1].

Danke für die Antworten

ciao

Ulf

[1]http://www.databasejournal.com/features/mysql/article.php /10897_3110171_1

Re: PHP Query Cache

am 10.04.2008 15:54:14 von steffen bruentjen

Ulf Seltmann wrote:

>Ich habe mal ein paar Lasttests gemacht und musste feststellen, dass die
>Anwendung mit PHP-Query-Cache (60 x mysql_query) nicht schneller ist,
>als nur mit MySQL-Query-Cache (1500 x mysql_query). Einzig die
>Lastverteilung auf die Datenkank macht mir Sorge. Und das wirkt sich ja
>produktiv anders aus, als auf meinem Testsystem (wo ich als einziger
>zugreife).

Wenn ich Dich richtig verstehe, hast Du damit herausgefunden, dass ein
PHP-Query-Cache (nennen wir es 'clientseitiger Query-Cache') nicht
schneller ist als ein serverseitiger Query-Cache. Das ist auch das,
was ich schrieb. Allerdings ist Dein Lasttest zu speziell; das
Ergebnis hängt übermäßig stark von der Umgebung und der Anwendung ab.
Zunächst mal:

1. Bei HTML/PHP wird ein (einfacher) Query-Cache auf Clientseite so
realisiert, dass bei jedem Seitenaufruf (das heißt auch pro Nutzer!)
eine Query auf dem Server ausgeführt wird. (Aus diesem Grund bringt
ein solcher Query-Cache nicht viel.) Dein Beispiel ignoriert, wie sich
die gleichen Queries (deren Ergebnisse also aus dem Query-Cache
gelesen werden können) verteilen.

2. Ein Query-Cache auf Serverseite erfordert für jede einzelne Query
Kommunikation mit dem Server. Derselbe Cache wird dafür jedoch von
allen Clients gleichermaßen verwendet. Hier hinkt Dein Lasttest
zugunsten eines clientseitigen Caches, weil es bei Dir nur einen
Nutzer gibt.

Kommunikation mit dem Server findet bei beiden Caching-Strategien
statt. (Das kann nur vermieden werden, wenn die Ergebnisse in
irgendeiner Weise auf Clientseite gespeichert werden (Session, Shared
Memory, Datenbank :). Das passiert übrigens auch häufig und oft
unbewusst. Es ist eine gute Technik, Objekte beim Instanziieren mit
Werten aus der Datenbank zu füllen (z.B. Benutzername) und dann in der
Session zu speichern. Damit wird beim nächsten Aufruf für
»Benutzername« keine Datenbankabfrage benötigt. Natürlich muss dabei
beachtet werden, dass Werte sich auch ändern können und Werte, die auf
diese Weise gespeicherte wurden, möglicherweise nicht synchron mit der
Datenbank sind.)

Prinzipiell hängt die Güte der beiden Cache-Strategien u.a. von diesen
Fragestellungen ab:

1. Wie viele verschiedene Nutzer rufen Seiten ab?
= Wie viele verschiedene Clients setzen Datenbank-Queries ab?
2. Wie viele identische Queries gibt es pro Seitenabruf?
3. Wie viele identische Queries gibt es über einen Seitenabruf hinweg?
3. Wie groß sind die Ergebnisse verschiedener Queries?
4. Wie ist das Verhältnis von UPDATEs und SELECTs?
5. Befindet sich die Datenbank auf einem entfernten Server? Wie hoch
sind die Verbindungskosten? Ist der Server belastet?

Also tendenziell mag eine wenig-frequentierte Seite mit vielen
gleichen Queries und einer Datenbank, welche auf einem separaten
Server liegt einen clientseitigen Query-Cache in ein besseres Licht
rücken. Du schreibst ja, dass tatsächlich enorm viele gleiche Queries
pro Seitenaufruf abgesetzt werden. Dann ist ein clientseitiger Cache
mit Sicherheit eine Option.


>Ich neige stark dazu die Performance-Optimierung an den Admin abzugeben :)
>
>Ein hilfreicher Text neben den hier geposteten Kommentaren war übrigens [1].
>[1]http://www.databasejournal.com/features/mysql/article.ph p/10897_3110171_1

Aha, die Wikipedia kann man also in Datenbankform herunterladen.
Ansonsten steht alles andere auch im MySQL-Handbuch.

Schöne Grüße, Steffen

--
Das Tastaturlayout für Programmierer:
http://eurkey.steffen.bruentjen.eu