Performance (Caching von aus MySQL generierten PHP-Objekten)
ScaraX
- php
0 dedlfix
0 Pragma1 Sven Rautenberg
Hi,
Bei meinem kleinen PHP-Framework kommt mittlerweile das Problem auf, dass ich bei jedem Seitenaufruf größere Datenmengen aus MySQL Datenbanken auslesen muss.
Damit das alles so fix wie möglich abläuft hab ich mir vorgestellt die Ergebnisse dieser Abfragen zu cachen.
Die Frage ist nun, welche Methode am besten ist.
Situation:
Ich habe eine MySQL-Tabelle "Module" mit den Feldern name (primary key), title, description, status und noch ein paar mehr.
Es werden sich wohl ca. 50-200 Datensätze in der Tabelle befinden.
Bei jedem Seitenaufruf benötige ich die Daten von geschätzten 10-20% der vorhandenen Module (immer unterschiedliche).
Mir fallen jetzt folgende Möglichkeiten ein diese Daten abzufragen:
1. Ich frage jedes benötigte Modul einzeln ab und erstelle mithilfe der Daten der Abfrage das passende PHP-Objekt.
2. Ich frage bei jedem Seitenaufruf alle Datensätze ab, erstelle in einer schleife alle PHP-Objekte und speichere diese in einem Array, auf welches ich dann zugreife wenn ein konkretes Modul benötigt wird.
3a. Ich speichere die einzelnen Module aus 1. in serialisierter Form in einer MySQL-Tabelle (Config), welche ich sowieso bei jedem Aufruf vollständig lade) und greife dann bei Bedarf auf diese Daten zurück.
wenn ein Modul geändert wird, wird der dazugehörige Config-Eintrag neu erstellt.
3b. wie 3a, allerdings speichere ich den in 2. gespeicherten Array mit allen Modulen in serialisierter Form in der Config-Tabelle und wandle diesen dann bei jedem Seitenaufruf zurück in einen Array, auf den ich dann bei Bedarf zugreifen kann.
Wenn ein Modul geändert wird bzw ein neues hinzukommt, wird der DB-Eintrag komplett neu erstellt.
4a. wie 3a, aber die Serialisierten Module werden nicht in der DB, sondern in (jeweils einer eigenen) Datei gespeichert.
4b. wie 3b, aber das Array wird in einer Datei gespeichert.
Noch zu erwähnen wäre, dass es neben der Modul-Tabelle noch weitere Objekte gibt, mit denen ich ähnlich verfahren wollte.
Da ich das Framework auf verschiedenen Systemen nutzen wollte kann ich zu verwendeter Hardware bzw PHP/MySQL-Konfiguration leider nichts sagen (sofern die PHP-Einstellungen sich nicht im PHP-Code selbst ändern lassen).
Ich freue mich schon auf eure kompetenten Antworten :)
MfG
ScaraX.
Hi!
Die Frage ist nun, welche Methode am besten ist.
Die mit der kürzesten Laufzeit.
Pause.
Hättest duu jetzt bestimmt nicht erwartet, oder? Aber mal im Ernst. Du musst das messen. Vorhersagen kann dir das keiner. Je nach Art der Daten und gesetzter Indexe kann ja schon das DBMS unterschiedliches Laufzeitverhalten für die gleiche Aufgabenstellung aufweisen.
Lo!
Hi!
Die Frage ist nun, welche Methode am besten ist.
Die mit der kürzesten Laufzeit.
Pause.
Hättest duu jetzt bestimmt nicht erwartet, oder? Aber mal im Ernst. Du musst das messen. Vorhersagen kann dir das keiner. Je nach Art der Daten und gesetzter Indexe kann ja schon das DBMS unterschiedliches Laufzeitverhalten für die gleiche Aufgabenstellung aufweisen.
Lo!
Doch, ich habe so eine Antwort befürchtet ;)
Ich hoffe aber das es hier im Forum jemanden gibt, der sich mit dieser Problematik bereits beschäftigt hat und seine Erfahrungen mit mir teilen kann, wodurch ich zumindest die ein oder andere Möglichkeit ausschließen kann...
MfG
ScaraX
Hi!
Ich hoffe aber das es hier im Forum jemanden gibt, der sich mit dieser Problematik bereits beschäftigt hat und seine Erfahrungen mit mir teilen kann, wodurch ich zumindest die ein oder andere Möglichkeit ausschließen kann...
Es wird keinen geben, der den Code, den du zusammenprogrammiert hast oder noch wirst, bereits getestet hat. Insofern ist jegliche Aussage, Variante A wird schneller sein als B ohne Kartenlegen oder dergleichen nicht möglich. Das was sich bei mir bewährt hat, kann bei dir komplett andere Resultate bringen, weil du es anders implementieren wirst. Generell gilt: alles was ausgeführt werden muss, kostet Laufzeit. Dinge, die vorbereitet sind, kosten eventuell weniger Laufzeit als das was noch erzeugt werden muss. Dabei kommt es jedoch auch darauf an, wie die Vorbereitung aussieht. Wenn sie erst noch aufwendig geparst werden muss, ...
Diese allgemeinen Grundsätze werden dir nicht viel Erkenntnisgewinn bringen, denn auf die kommt man auch, wenn man darüber nachdenkt.
Lo!
Sven Rautenberg hat hier einmal sehr schön ausgeführt, warum man es erst "tunen" sollte, wenn es wirklich nötig wird. 50 - 200 Datensätze hört sich nicht so an, als ob es bereits soweit ist ;-)
Konzentrier Dich auf sauberes Design und vergiss den Rest erstmal.
Sven Rautenberg hat hier einmal sehr schön ausgeführt, warum man es erst "tunen" sollte, wenn es wirklich nötig wird. 50 - 200 Datensätze hört sich nicht so an, als ob es bereits soweit ist ;-)
Konzentrier Dich auf sauberes Design und vergiss den Rest erstmal.
Hi,
Es sind 50-200 Datensätze in der "Modules"-Tabelle.
Daneben gibt es aber noch ca. 10 weitere Tabellen mit ähnlichen Größen.
Und das bei jedem Aufruf meiner Seite kann IMO schon auf die Performance gehen...
MfG
ScaraX
Es sind 50-200 Datensätze in der "Modules"-Tabelle.
Daneben gibt es aber noch ca. 10 weitere Tabellen mit ähnlichen Größen.Und das bei jedem Aufruf meiner Seite kann IMO schon auf die Performance gehen...
Und _was_ bei jedem Aufruf Deiner Seite? 10 * 200 = 2000 Datensätze sind immer noch Peanuts, 10 Querys per Seitenaufruf allerdings ungünstig, das stimmt. Das wären Sie aber auch schon bei zwei Datensätzen pro Tabelle.
Ohne Dein "Framework" zu kennen: mich dünkt, Du hast ein Problem im Design / Datenmodell. Daher nochmal der Hinweis: Kümmer Dich ums Design!
Ohne Dein "Framework" zu kennen: mich dünkt, Du hast ein Problem im Design / Datenmodell. Daher nochmal der Hinweis: Kümmer Dich ums Design!
Kann sein dass mein Datenmodell nicht optimal ist...
Es gibt mei meinem Framework z.B. Module, Widgets (welche in der Sidebar geladen werden), Hooks und Templates, welche alle in einer eigenen Tabelle gespeichert sind.
Von allem wird bei einem Seitenaufruf in der Regel mehr als ein Datensatz benötigt.
Daher macht es IMO auch am meisten Sinn, diese Daten in serialisierter Form zu Speichern und zusammen in einem Query auszulesen.
Hier stellt sich nun die Frage, wie performant PHPs unserialize() ist ;)
MfG
ScaraX
Kann sein dass mein Datenmodell nicht optimal ist...
Kümmer Dich JETZT drum, statt Zeit mit Tuning zu vergeuden.
Es gibt mei meinem Framework z.B. Module, Widgets (welche in der Sidebar geladen werden), Hooks und Templates, welche alle in einer eigenen Tabelle gespeichert sind.
Von allem wird bei einem Seitenaufruf in der Regel mehr als ein Datensatz benötigt.
Diese Daten stehen in keinerlei Bezug zueinander? Klingt komisch. Wenn Sie in Bezug stehen: Schonmal was von Relationen / JOIN gehört?
Daher macht es IMO auch am meisten Sinn, diese Daten in serialisierter Form zu Speichern und zusammen in einem Query auszulesen.
Am meisten Sinn macht zunächst ein sauberes Design. Ich will Dich damit nicht nerven, es ist die Wahrheit!
Hier stellt sich nun die Frage, wie performant PHPs unserialize() ist ;)
Nein. Das riecht nach Holzweg. Aber musst Du wissen ;-)
Moin!
Bei meinem kleinen PHP-Framework kommt mittlerweile das Problem auf, dass ich bei jedem Seitenaufruf größere Datenmengen aus MySQL Datenbanken auslesen muss.
Du meinst kleinere Datenmengen.
Damit das alles so fix wie möglich abläuft hab ich mir vorgestellt die Ergebnisse dieser Abfragen zu cachen.
Hast du gemessen, wie lange ein Seitenaufruf insgesamt, und detailliert je Datenbankabfrage zeitlich braucht? Tu das. Denn nur mit diesen Messergebnissen (gemittelt über mehrere einzelne Seitenaufrufe) weißt du, wann sich durch Änderung was verbessert.
Die Frage ist nun, welche Methode am besten ist.
MySQL hat einen schönen Query-Cache. Die exakt gleiche Anfrage wird also beim zweiten Mal schon aus dem Cache beantwortet, sofern es sich um eine statische Anfrage handelt. Bestandteile wie "NOW()" sind nicht statisch und deshalb nicht cachebar.
Situation:
Ich habe eine MySQL-Tabelle "Module" mit den Feldern name (primary key), title, description, status und noch ein paar mehr.
Es werden sich wohl ca. 50-200 Datensätze in der Tabelle befinden.
Peanuts. Dafür baut man sich keinen Extra-Cache.
Bei jedem Seitenaufruf benötige ich die Daten von geschätzten 10-20% der vorhandenen Module (immer unterschiedliche).
Also 5 bis 40 Datensätze? Peanuts. Dafür baut man sich keinen Cache.
Mir fallen jetzt folgende Möglichkeiten ein diese Daten abzufragen:
- Ich frage jedes benötigte Modul einzeln ab und erstelle mithilfe der Daten der Abfrage das passende PHP-Objekt.
"Separation of concern" ist definitiv die Methode, die man in OOP haben will.
Allerdings fasst du die Sache vermutlich von der falschen Seite an, denn das Objekt erstellt sich selbst, indem es ggf. die Datenbank befragt - es wird nicht mit den Infos aus der Datenbank manuell befüllt.
- Ich frage bei jedem Seitenaufruf alle Datensätze ab, erstelle in einer schleife alle PHP-Objekte und speichere diese in einem Array, auf welches ich dann zugreife wenn ein konkretes Modul benötigt wird.
Negativ. Du instanziierst ein Objekt genau dann, wenn du es benötigst, und fragst erst genau dann die dazu gehörenden Daten ab.
3a. Ich speichere die einzelnen Module aus 1. in serialisierter Form in einer MySQL-Tabelle (Config), welche ich sowieso bei jedem Aufruf vollständig lade) und greife dann bei Bedarf auf diese Daten zurück.
wenn ein Modul geändert wird, wird der dazugehörige Config-Eintrag neu erstellt.
3b. wie 3a, allerdings speichere ich den in 2. gespeicherten Array mit allen Modulen in serialisierter Form in der Config-Tabelle und wandle diesen dann bei jedem Seitenaufruf zurück in einen Array, auf den ich dann bei Bedarf zugreifen kann.
Wenn ein Modul geändert wird bzw ein neues hinzukommt, wird der DB-Eintrag komplett neu erstellt.
4a. wie 3a, aber die Serialisierten Module werden nicht in der DB, sondern in (jeweils einer eigenen) Datei gespeichert.4b. wie 3b, aber das Array wird in einer Datei gespeichert.
Serialisierte Objekte bringen dir lediglich eine zusätzlichen Schicht Komplexität ins Spiel, die du nach meinem Eindruck noch nicht handhaben kannst, und die dir absolut nichts bringt.
Noch zu erwähnen wäre, dass es neben der Modul-Tabelle noch weitere Objekte gibt, mit denen ich ähnlich verfahren wollte.
Da ich das Framework auf verschiedenen Systemen nutzen wollte kann ich zu verwendeter Hardware bzw PHP/MySQL-Konfiguration leider nichts sagen (sofern die PHP-Einstellungen sich nicht im PHP-Code selbst ändern lassen).
Ich bin ja schon zitiert worden, und es ist wahr: Du hast, rein von der Datenmenge her, absolut keinen Grund, schon irgendwelches Tuning mit Caches anzuwenden. Wenn du das jetzt schon als notwendig erachtest, ist dein Design sehr kaputt.
Und vermutlich hast du bis jetzt auch keinen Überblick, wo dein angebliches Performanceproblem denn wirklich seine Ursache hat, weil dir keine harten Fakten zum Zeitverhalten deiner Skripte vorliegen.
Ändere das! microtime(true) liefert dir eine schöne, hochaufgelöste Zeitangabe in eine Variable. Du kannst aber natürlich auch das xdebug-Modul zum Profiling einsetzen und mit kcachegrind nachgucken, was dein Code wie lange und wie häufig tut.
- Sven Rautenberg
Hallo,
Hast du gemessen, wie lange ein Seitenaufruf insgesamt, und detailliert je Datenbankabfrage zeitlich braucht? Tu das. Denn nur mit diesen Messergebnissen (gemittelt über mehrere einzelne Seitenaufrufe) weißt du, wann sich durch Änderung was verbessert.
Fuer das allgemeine Testen der Performance bzw. Bottlenecks bietet sich WinCacheGrind an.
Das Tool liest die CacheGrinds vom Apache ein, und bietet eine detaillierte Auflistung der einzelnen Funktionsaufrufe inklusive der dafuer verbrauchten Zeit.
MfG
Peter