junker_wentzel: Performance: include vs. MySQL

n'Abend,

ich bin grad mit einem mehr oder weniger privatem Projekt beschaeftigt(welches aber online gehen soll), und wie das so ist, kriegt man immer, wenn man schon recht weit ist, Ideen, wie man das ganze vereinfachen/verbessern kann. Dazu muss ich sagen, ich bin ein totaler Freizeit-Programmierer, aber lerne gerne dazu ;)

Ich habe eine Webseite, die ihren Inhalt aus einer Datenbank bezieht (Bewertungen und Kommentare). Wenn jetzt die Webseite groesser wird (ich weiss, utopische Vorstellung), mehr Besucher bekommt und die Datenbank dementsprechend mehr Kommentare/Bewertungen enthaelt, habe ich die Befuerchtung, dass die Performance leidet, wegen den vielen Datenbank-Abfragen und dem Traffic.

Jetzt meine Frage:
Was ist programmiertechnisch und performancetechnisch besser/schneller:
1. Bei jedem Aufruf der Seite die Datenbank befragen und die Daten darstellen.
oder
2. Ein Skript schreiben, welches basierend auf der Datenbank eine HTML-Seite entwirft. Dann wird auf der Seite, die die Benutzer aufrufen, diese Seite includiert. Nur wenn der Nutzer ein Kommentar oder eine Bewertung macht, wird per Aufruf eine Datenbankverbindung hergestellt und die Datenbank aktualisiert, per Skript, dann wird wieder die neue HTML-Seite includiert.

Also eigentlich ist die Frage MySQL-Abfragen vs. Einbindungen einer HTML-Seite.

Wie kann man eigentlich ein Skript, welches in einer anderen Datei liegt aufrufen und ihm Parameter uebergeben? Per include, oder gibt es da noch andere Wege?

Bisschen viel Text, so spaet am Abend ;)

Junker v. Wentzel(-Tronka)

  1. Hi,

    ich bin grad mit einem mehr oder weniger privatem Projekt beschaeftigt(welches aber online gehen soll), und wie das so ist, kriegt man immer, wenn man schon recht weit ist, Ideen, wie man das ganze vereinfachen/verbessern kann. Dazu muss ich sagen, ich bin ein totaler Freizeit-Programmierer, aber lerne gerne dazu ;)

    mittels geschickt eingesetzter Indizes (u.a.) ist der Performance-Verlust logarithmisch anstatt linear oder sogar exponenziell. Die Anzahl der DB-Requests sollte unbedingt auf ein Minimum reduziert sein.

    Was ist programmiertechnisch und performancetechnisch besser/schneller:

    1. Bei jedem Aufruf der Seite die Datenbank befragen und die Daten darstellen.
      oder
    2. Ein Skript schreiben, welches basierend auf der Datenbank eine HTML-Seite entwirft. Dann wird auf der Seite, die die Benutzer aufrufen, diese Seite includiert. Nur wenn der Nutzer ein Kommentar oder eine Bewertung macht, wird per Aufruf eine Datenbankverbindung hergestellt und die Datenbank aktualisiert, per Skript, dann wird wieder die neue HTML-Seite includiert.

    Eine schnelle DB-Abfrage, die ermittelt, ob mehrere umfangreiche DB-Abfragen nötig sind und ansonsten die gecachte Variante verwendet, wäre ebenfalls eine Möglichkeit. Wenn öfter gespeichert als gelesen wird, kann(!) das die Performance schonen.

    Also eigentlich ist die Frage MySQL-Abfragen vs. Einbindungen einer HTML-Seite.

    In erster Linie solltest Du Dich mit der Optimierung des DB-Layouts beschäftigen. EXPLAIN ist Dein Freund, Erfahrung Dein Verbündeter.

    Wie kann man eigentlich ein Skript, welches in einer anderen Datei liegt aufrufen und ihm Parameter uebergeben? Per include, oder gibt es da noch andere Wege?

    Nun ja, es könnten sich Variablen anbieten ...

    Cheatah

    --
    X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
    X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
    X-Will-Answer-Email: No
    X-Please-Search-Archive-First: Absolutely Yes
    1. Hey

      mittels geschickt eingesetzter Indizes (u.a.) ist der Performance-Verlust logarithmisch anstatt linear oder sogar exponenziell. Die Anzahl der DB-Requests sollte unbedingt auf ein Minimum reduziert sein.

      Das ist sogar mir klar ;)

      Eine schnelle DB-Abfrage, die ermittelt, ob mehrere umfangreiche DB-Abfragen nötig sind und ansonsten die gecachte Variante verwendet, wäre ebenfalls eine Möglichkeit. Wenn öfter gespeichert als gelesen wird, kann(!) das die Performance schonen.

      Die DB-Abfragen sind nicht umfangreich, meistens wird ein Wert/Feld geaendert/neu erstellt. Und es wird auf jeden Fall mehr gelesen als geaendert/gespeichert.

      In erster Linie solltest Du Dich mit der Optimierung des DB-Layouts beschäftigen. EXPLAIN ist Dein Freund, Erfahrung Dein Verbündeter.

      Das DB-Layout ist nicht sehr umfangreich und es wird bestimmt auch nicht viele Datensaetze (im Vergleich zu kommerziellen Datenbanken) enthalten, trotzdem werde ich mich mal mit den Vorschlaegen auseinander setzt.

      Trotzdem bleibt bei mir eine (grosse) Unklarheit:

      Eine schnelle DB-Abfrage, die ermittelt, ob mehrere umfangreiche DB-Abfragen nötig sind

      Wie stell ich das fest? Habe keinerlei Erfahrung auf dem Gebiet, Hilfestellung waere sinnvoll.
      Und wie kann ein php-Script erkennen, dass es sich selbst "gecachten" soll, also keine neuen DB-Daten anbietet, weil die Datenbank noch immer auf dem alten Stand ist? Waere da meine Vorgehensweise, nur DB-Kontakt herzustellen, wenns noetig ist, und sonst die erstelle HTML-Datei includen, im Ansatz richtig/ in Ordnung?

      Nun ja, es könnten sich Variablen anbieten ...

      Ich meinte auch eher, ob es hier andere Wege wie include gibt ;)

      1. Moin!

        Trotzdem bleibt bei mir eine (grosse) Unklarheit:

        Eine schnelle DB-Abfrage, die ermittelt, ob mehrere umfangreiche DB-Abfragen nötig sind

        Wie stell ich das fest? Habe keinerlei Erfahrung auf dem Gebiet, Hilfestellung waere sinnvoll.
        Und wie kann ein php-Script erkennen, dass es sich selbst "gecachten" soll, also keine neuen DB-Daten anbietet, weil die Datenbank noch immer auf dem alten Stand ist? Waere da meine Vorgehensweise, nur DB-Kontakt herzustellen, wenns noetig ist, und sonst die erstelle HTML-Datei includen, im Ansatz richtig/ in Ordnung?

        Beim Caching ist folgendes Muster typisch:

        Der tatsächliche Aufruf ruft nicht mehr stur direkt die aufwendige Berechnungsaktion auf, sondern prüft zunächst mal, ob dafür überhaupt ein Anlass besteht. Dazu muss in irgendeiner Weise der Zustand "Cache ist veraltet, muss neu" ermittelt werden. Und diese Operation, zusammen mit dem Auslesen aus dem Cache, ist nicht unbedingt einfacher bzw. schneller. Je nach Häufigkeit der Cache-Aktualisierung kommt auch das Neuschreiben des Caches als Zeitfaktor hinzu.

        Nur mal so als Rechenbeispiel: Wenn die normale Operation 10 Zeiteinheiten benötigt, das Ermitteln des Cache-Inhalts 2 Zeiteinheiten, das Auslesen des Caches ebenfalls 2 Zeiteinheiten, und das Neuschreiben des veralteten Caches 5 Zeiteinheiten, dann hast du folgende Muster:

        Normalzustand ohne Caching: 10
        Cache-Miss: 2 + 10 + 5 = 17 (Cachezustand ermitteln, die eigentliche Operation voll durchführen, und in Cache speichern)
        Cache-Hit: 2 + 2 = 4 (Cachezustand ermitteln und auslesen)

        Hundert Aufrufe ohne Caching:
        100 * 10 Zeiteinheiten ohne Cache = 1000 Einheiten

        Wenn viele hundert Lesevorgänge den Cache nutzen, ist Caching in DIESER Zeitverteilung vorteilhaft:
        99 * 4 Zeiteinheiten mit Cache + 1 * 17 Einheiten ohne Cache = 413 Einheiten

        Wenn hingegen die Hit- und Miss-Vorgänge 50:50 verteilt sind, weil sich Dinge schnell ändern, sieht es nicht gut aus:
        50 * 17 Einheiten (Cache neu füllen) + 50 * 4 Einheiten (Cache lesen) = 1050 Einheiten

        Das ist langsamer, als die Originalen 1000 Einheiten ohne Caching. :)

        Der Mysql-Query-Cache beispielsweise sitzt vorteilhaft direkt an der Quelle, und kann Veränderungen an der Tabelle, die im Cache steckt, direkt kontrollieren: Schreibzugriffe auf die Tabelle invalidieren den Cache automatisch.

        Dummerweise ist der Cache ein ziemlich dummer: Wenn dein Query nicht aufs Zeichen genau vorher schon einmal erfolgte, oder wenn das Ergebnis aufgrund von dynamischen Funktionen ermittelt wird, wie z.B. NOW() (die aktuelle Uhrzeit ändert sich jede Sekunde, das Query-Ergebnis deshalb potentiell auch), kann MySQL nichts cachen. Da muss man also durch Messen und Erfahrungswerte seine Querys so optimieren, dass man in den Genuss des Caches kommt.

        - Sven Rautenberg

        1. Abend,

          nochmal vielen Dank fuer die ausfuehrliche Erklaerung! Aber so genau wollte ich es auch nicht wissen (bezogen auf den rechnerischen Teil) ;)

          Beim Caching ist folgendes Muster typisch:

          Der tatsächliche Aufruf ruft nicht mehr stur direkt die aufwendige Berechnungsaktion auf, sondern prüft zunächst mal, ob dafür überhaupt ein Anlass besteht. Dazu muss in irgendeiner Weise der Zustand "Cache ist veraltet, muss neu" ermittelt werden.

          Da happerts schon mit meinem Verstaendnis :D
          Der Cache ist ja Client-abhaengig, oder? (Wenn das falsch ist, sagen!)
          Dass heisst, der Pruefungs-Teil muss pruefen, ob die Datenbank seit dem letzten Caching veraendert wurde. Wie prueft man sowas?

          Mir ist das ganze noch etwas unklar. Waere praktisch wenn mir jemand mein Vorschlag, denn ich in den vorherigen Postings geaeussert habe, mal zerlegt und die Nachteile aufzeigt ;)

          Martin Junker

          1. Moin!

            Abend,

            nochmal vielen Dank fuer die ausfuehrliche Erklaerung! Aber so genau wollte ich es auch nicht wissen (bezogen auf den rechnerischen Teil) ;)

            Beim Caching ist folgendes Muster typisch:

            Der tatsächliche Aufruf ruft nicht mehr stur direkt die aufwendige Berechnungsaktion auf, sondern prüft zunächst mal, ob dafür überhaupt ein Anlass besteht. Dazu muss in irgendeiner Weise der Zustand "Cache ist veraltet, muss neu" ermittelt werden.

            Da happerts schon mit meinem Verstaendnis :D
            Der Cache ist ja Client-abhaengig, oder? (Wenn das falsch ist, sagen!)
            Dass heisst, der Pruefungs-Teil muss pruefen, ob die Datenbank seit dem letzten Caching veraendert wurde. Wie prueft man sowas?

            Wenn der Cacheeintrag Datum und Uhrzeit der letzten Änderung enthält, kann man in der Datenbank nachfragen, was dort das aktuellste Datum ist. Wenn das identisch mit dem Cache ist, hat sich nichts geändert.

            Aber du erkennst das Problem: Caching geht nicht ohne das Originalsystem. Deshalb kann das Ermitteln der Aktualität des Caches fast genauso aufwendig sein, wie die Originalanfrage. Es hängt entschieden davon ab, um welche Art von Anfragen es geht.

            Es gibt natürlich eine Alternative: Der Cache kann sich auf einfach eine Zeit lang pauschal als aktuell erklären, und nach Ablauf einer gewissen Zeit wird er mit frischen Daten befüllt.

            Andererseits eröffnen sich auch komplett neue Fehlermöglichkeiten: Wenn eine Website mit einem Cache performanter wird und alles prima läuft, kommt es dennoch irgendwann einmal zu der Situation, dass der Cache aktualisiert werden muss. Wenn das zu einem Zeitpunkt mit hoher Last passiert, stellen viele gleichzeitige Requests fest, dass der Cache nicht mehr aktuell ist. Wenn das Caching ungünstig programmiert ist, werden alle diese parallelen Requests jetzt die aufwendige Originaloperation, z.B. den DB-Query ausführen wollen - und die Datenbank bricht spontan unter dieser Last zusammen.

            Ebenfalls problematisch ist, wenn der Cache-Eintrag parallel von mehreren Requests aus aktualisiert werden soll, die DB also den Ansturm bewältigt, aber nun das frische Ergebnis zwischenzuspeichern ist. Klare Sache: Locking verhindert, dass zwei Requests sich gegenseitig das Ergebnis zerstören. Das wiederum verhindert aber, dass diese parallelen Requests performant parallel abgearbeitet werden können, denn sie müssen ALLE nacheinander das identische Ergebnis in den Cache speichern. Und solange der Cache nicht final gespeichert wurde, müssen alle neuen Requests den Cache ja aktualisieren.

            Gegen diese Problemklassen gibt es natürlich Gegenstrategien, die man einsetzen kann, aber du merkst sicherlich, dass Caching nicht so simpel ist, wie es auf den ersten Blick aussieht.

            - Sven Rautenberg

  2. Moin!

    Ich habe eine Webseite, die ihren Inhalt aus einer Datenbank bezieht (Bewertungen und Kommentare). Wenn jetzt die Webseite groesser wird (ich weiss, utopische Vorstellung), mehr Besucher bekommt und die Datenbank dementsprechend mehr Kommentare/Bewertungen enthaelt, habe ich die Befuerchtung, dass die Performance leidet, wegen den vielen Datenbank-Abfragen und dem Traffic.

    Gegen den Traffic kannst du wenig tun - den erschlägt man in der Regel durch einen Webserver-Cluster mit Load-Balancing.

    Die Menge an DB-Abfragen hingegen kann man bei Bedarf einer manuellen Optimierung unterziehen.

    Jetzt meine Frage:
    Was ist programmiertechnisch und performancetechnisch besser/schneller:

    1. Bei jedem Aufruf der Seite die Datenbank befragen und die Daten darstellen.
      oder
    2. Ein Skript schreiben, welches basierend auf der Datenbank eine HTML-Seite entwirft. Dann wird auf der Seite, die die Benutzer aufrufen, diese Seite includiert. Nur wenn der Nutzer ein Kommentar oder eine Bewertung macht, wird per Aufruf eine Datenbankverbindung hergestellt und die Datenbank aktualisiert, per Skript, dann wird wieder die neue HTML-Seite includiert.

    Weder, noch. Bzw.: Sowohl als auch.

    Von der Performance her ist die Auslieferung einer komplett statisch auf Festplatte liegenden Datei unschlagbar schnell. Aber diese Datei so zusammenzustellen, dass die Dynamic der Site realisiert wird ist programmtechnisch sehr aufwendig.

    Deshalb gilt umgekehrt: Eine Site voll dynamisch auszugeben ist programmtechnisch sehr schnell realisiert - aber die Performance ist naturgemäß nicht ganz so schnell.

    Der Mittelweg würde bedeuten: Wichtige, häufige und selten veränderte Aufrufe der dynamischen Site werden in einem Cache gehalten. Viele von denen sind standardmäßig im Spiel, wenn man sie intelligent einsetzt, beispielsweise der MySQL-Query-Cache. Andere Caches kann man natürlich manuell ins Spiel bringen - sofern das Abrufen des Caches nicht langsamer ist, als der Originalvorgang (messen!).

    Wie kann man eigentlich ein Skript, welches in einer anderen Datei liegt aufrufen und ihm Parameter uebergeben? Per include, oder gibt es da noch andere Wege?

    Das würde man vermutlich versuchen zu vermeiden.

    - Sven Rautenberg

    1. Servus,

      ich find das Forum hier super: Sobald man was fragt, wird man gleich mit Antworten ueberhaeuft, die dann in einem gleich wieder Tausend Fragen aufwerfen und einen verwirren ;)

      Die Menge an DB-Abfragen hingegen kann man bei Bedarf einer manuellen Optimierung unterziehen.

      Es sind nicht viele DB-Abfragen, ich mach bestimmt wieder aus einer Fliege einen Elefanten.

      Weder, noch. Bzw.: Sowohl als auch.

      Von der Performance her ist die Auslieferung einer komplett statisch auf Festplatte liegenden Datei unschlagbar schnell. Aber diese Datei so zusammenzustellen, dass die Dynamic der Site realisiert wird ist programmtechnisch sehr aufwendig.

      »»
      Und wenn diese Datei nur erstellt wird, wenn es eine Datenbankveraenderung gegeben hat, ergo etwas in die Datenbank eingetragen werden musste und daraufhin die Datenbank per Script in eine HTML-Datei veraendert wird, und diese HTML-Datei dann includiert wird, gehoert dass auch zu der oben genannten Variante?

      Der Mittelweg würde bedeuten: Wichtige, häufige und selten veränderte Aufrufe der dynamischen Site werden in einem Cache gehalten. Viele von denen sind standardmäßig im Spiel, wenn man sie intelligent einsetzt, beispielsweise der MySQL-Query-Cache. Andere Caches kann man natürlich manuell ins Spiel bringen - sofern das Abrufen des Caches nicht langsamer ist, als der Originalvorgang (messen!).

      Das Problem ist ja, ich weiss ja nicht, wie oft etwas geaendert wird. Kann man auch, bei einer Tabelle, die ganze Tabelle cachen und bei Bedarf (wenn es eine Aenderung in der DB gab) einen Zelleninhalt "updaten"?

      Wie kann man eigentlich ein Skript, welches in einer anderen Datei liegt aufrufen und ihm Parameter uebergeben? Per include, oder gibt es da noch andere Wege?

      Das würde man vermutlich versuchen zu vermeiden.

      Also include ist in der hinsicht schlecht? Wie macht das dann, z.B. joomla?

      Vielen Dank schonmal,

      1. Moin!

        Die Menge an DB-Abfragen hingegen kann man bei Bedarf einer manuellen Optimierung unterziehen.

        Es sind nicht viele DB-Abfragen, ich mach bestimmt wieder aus einer Fliege einen Elefanten.

        Vermutlich. Optimiere nichts, was sich noch nicht als Problem erwiesen hat, denn jede vorzeitige Optimierung ist vermutlich falsch - also nicht bedarfsgerecht.

        Von der Performance her ist die Auslieferung einer komplett statisch auf Festplatte liegenden Datei unschlagbar schnell. Aber diese Datei so zusammenzustellen, dass die Dynamic der Site realisiert wird ist programmtechnisch sehr aufwendig.
        »»
        Und wenn diese Datei nur erstellt wird, wenn es eine Datenbankveraenderung gegeben hat, ergo etwas in die Datenbank eingetragen werden musste und daraufhin die Datenbank per Script in eine HTML-Datei veraendert wird, und diese HTML-Datei dann includiert wird, gehoert dass auch zu der oben genannten Variante?

        Eine Datenbankveränderung betrifft nur selten exakt eine einzige generierte Datei.

        Nur mal angenommen, es wird die Navigation geändert: Dann müssten alle Seiten neu generiert werden. Das kann ein deutlich zeitaufwendigerer Vorgang werden, als das schlichte Aktualisieren der Datenbank. Und er ist in der Regel auch nicht so simpel durchzuführen. Die Schwierigkeit besteht hierbei üblicherweise im Problem, zu erkennen, welche Seiten von der Änderung alle betroffen sind.

        Der Mittelweg würde bedeuten: Wichtige, häufige und selten veränderte Aufrufe der dynamischen Site werden in einem Cache gehalten. Viele von denen sind standardmäßig im Spiel, wenn man sie intelligent einsetzt, beispielsweise der MySQL-Query-Cache. Andere Caches kann man natürlich manuell ins Spiel bringen - sofern das Abrufen des Caches nicht langsamer ist, als der Originalvorgang (messen!).

        Das Problem ist ja, ich weiss ja nicht, wie oft etwas geaendert wird. Kann man auch, bei einer Tabelle, die ganze Tabelle cachen und bei Bedarf (wenn es eine Aenderung in der DB gab) einen Zelleninhalt "updaten"?

        Man wird heutzutage seinen Datenbankserver immer versuchen so zu konfigurieren, dass die gesamte Datenbank im RAM gehalten werden kann. Das gilt natürlich nicht unbedingt für Shared Hosting, aber definitiv für dedizierte Virtual Server und echte Server, die man vollständig selbst administrieren kann. Dadurch entstehen dann gerne mal Servercluster mit 64 GB RAM pro Maschine nur für die DB.

        Solange du grundsätzlich noch kein DB-Performanceproblem HAST, solltest du dir über Optimierung noch nicht allzu sehr Gedanken machen.

        Wie kann man eigentlich ein Skript, welches in einer anderen Datei liegt aufrufen und ihm Parameter uebergeben? Per include, oder gibt es da noch andere Wege?

        Das würde man vermutlich versuchen zu vermeiden.
        Also include ist in der hinsicht schlecht? Wie macht das dann, z.B. joomla?

        Die problematische Stelle ist: Wie kommt ausführbarer Code in die Datei, die mit Include eingebunden wird? Ich würde dir pauschal zutrauen, dass du auf Anhieb mehr als eine Sicherheitslücke da reinprogrammierst. :)

        - Sven Rautenberg