SQL_CALC_FOUND_ROWS führt zu unerklärlichen Abstürzen

Heute mal ein Beitrag über ein Thema, das mir wochen- wenn nicht sogar monatelang Kopfzerbrechen bereitet hat. Und zwar fiel mein Server immer mal aus unerklärlichen Gründen aus. Die Prozesse hingen sich auf und Feierabend. Natürlich gab es keine Reproduzierbarkeit des Fehlers – teilweise lief der Server auch mehrere Tage in Folge problemlos und dann krachte es wieder. Wie immer ohne Einträge in Logs oder sonstwo. Nun endlich habe ich das Problem gefunden…

Natürlich war der Fehler hausgemacht. Doch wollte ich es nicht wahrhaben, wo ich doch jedes Script nochmal untersucht habe, mich durch eingesetzte Fremdscripte gewühlt habe, die Datenbanken penibel überprüft habe.
Kurz gesagt: Es lag an einer hier im Blog empfohlenen SQL-Anweisung: SQL_CALC_FOUND_ROWS.

Diese Anweisung ist ja eigentlich ganz nützlich, erspart sie doch eine zusätzliche Abfrage für die Gesamtanzahl an Datensätzen, wenn man das Gesamtergebnis auf mehrere Seiten aufteilt. Schon damals kamen in den Kommentaren Stimmen gegen diese Maßnahme auf.
Marcel meinte Bezug nehmend auf einen Blogbeitrag vom MySQL Performance Blog:

Bei so einfachen Tabellen die auch noch Keys auf jeder Spalte haben, wie bei mysqlperformance ist Count natürlich schneller – hier geht es aber definitiv um komplexere Queries als bei mysqlperforrrrrmance gezeigt.

Damit hat er Recht. Ich habe es ja nicht umsonst geschrieben. Bei komplexen Abfragen wie Suchen mit MATCH oder LIKE-Funktion, GROUPing usw. spart SQL_CALC_FOUND_ROWS schon Zeit. Die eine Abfrage dauert zwar minimal länger, aber man spart sich eben eine zusätzliche Abfrage, die nur das Zählen der Gesamtzahl der Datensätze übernimmt.

Alex wies dann daraufhin, dass tatsächlich durch SQL_CALC_FOUND_ROWS ein Mehraufwand entsteht (weil ich ursprünglich geschrieben habe, dass kein Mehraufwand entstehen würde). Außerdem beschrieb er, dass es durchaus Abfragen gibt, die mit 2 Abfragen schneller sind als mit einer SQL_CALC_ROWS-Abfrage. Das stimmt natürlich (siehe oben).

Um zurück zu den Abstürzen zu kommen: Ich suchte also das gesamte Netz durch, weil man ja eigentlich nie der erste ist, der ein bestimmtes Problem hat. Irgendwann hab ich dann vor lauter Verzweiflung mal auf meinen eigenen Blogbeitrag geklickt – eben jenen zu SQL_CALC_FOUND_ROWS.
Und da lese ich mir die Kommentare durch und stoße auf den von mydeams:


In dem Projekt wo ich diese Methode genutzt habe, werden sehr viele MySQL Abfrage erstellt. ca. 1000 besucher hat die Seite am Tag. Mir/Uns ist aufgefallen, dass die Seite bzw. die MySQL DB sich nach na Zeit aufgehangen hat. Wegen dieses befehls. Habe ich das in der alten konventionellen Art gemacht mit nem entsprechendem Count … traten die Abstürze nimmer auf.

In der Prozessorliste von PHPMyAdmin hing er sich immer im Prozess “copy to tmp table” auf. Ich muss dazu aber auch sagen, dass die MySQL abfrage recht mächtig war, mit LIKE, LEFT JOIN etc. pp.

Ich griff also damit nach dem letzten Strohhalm und ersetzte alle SQL_CALC_FOUND_ROWS-Befehle durch die traditionelle 2-Abfragen-Methode mit COUNT().
Und das unglaubliche trat ein: Wie von mydeams prophezeit hatten die Abstürze dadurch tatsächlich eine Ende. Ein ganz großes Dankeschön an dieser Stelle! Deshalb freue ich ich über jeden Kommentar – er kann mal noch seeehr nützlich werden!

Ergo ziehe ich meine Empfehlung von SQL_CALC_FOUND_ROWS wieder zurück. Ob es an meiner Konfiguration lag, ob MySQL einen Bug hat, ich weiß es nicht. Ich weiß aber, dass ich in Zukunft einen großen Bogen um diese Funktion mache, denn es ist mir jetzt auch egal, ob der Seitenaufbau bei der Suche nun 0,2 Sekunden länger dauert, denn Performanceoptimierung darf natürlich nie auf Kosten der Stabilität gehen.

Jan hat 152 Beiträge geschrieben

8 Kommentare zu “SQL_CALC_FOUND_ROWS führt zu unerklärlichen Abstürzen

  1. bannerweb sagt:

    Genau die oben beschriebenen Probleme habe ich teilweise auch in meinen Applikationen. Werde nun genau so vorgehen wie Jan und auf eine höhere Stabilität hoffen (allerdings hat sich mein Server nicht ganz so häufig aufgehängt)…

  2. narkaT sagt:

    Wir verwenden diese methode seit einiger zeit erfolgreich
    in einem system welches pro tag ca 6 – 10k anfragen zu
    bewältigen hat.

    bis jetzt hatten wir noch keine Probleme 😉

    das ganze liegt auf einem gentoo system mit mysql 5.0.51.

  3. Dennis sagt:

    Hallo,

    ich setze auch sql_calc_found rows ein und hatte noch keine probleme damit.
    Ich muss dazusagen, dass in der tabelle auch nicht viele datensätze sind und keine komplizierten Abfragen. aber nun gut es funktioniert..muss ich also nichts umbauen oder wie seht ihr das?

  4. GhostGambler sagt:

    Wenn kein Join drin ist, sehe ich jetzt spontan keinen Grund den Query abzuändern.
    Sobald Joins in Spiel kommen würde ich tendenziell gucken, ob das simple Zählen sich nicht auch ohne den Join realisieren lässt – wenn ja, dann einen separaten COUNT-Query.
    Und ansonsten nur wenn es Probleme macht, ggf. ist/war das einfach nur ein Bug unter bestimmten Voraussetzungen, den die Hälfte der Menschheit niemals zu Gesicht bekommen. Könnte ja mal einer Googeln, hab ich keine Lust zu ^^,

  5. mydeams sagt:

    Hallo,
    es freut mich dass ich Dir mit meinem Post helfen konnte und dass also meine Vermutung durch dein Post sogar bestätigt wurde.

    Lieben Gruß,
    myDeams

  6. MKay sagt:

    Hi,

    ich musste leider die gleiche Erfahrung machen. Über Nacht war meine Webseite nicht mehr erreichbar. Der Hoster meinte, dass meine SQL-Anfragen den Server massiv belegt hatten, sodass die Prozesse hängen geblieben sind.

    Da meine Abfrage nur aus SELECT + JOINs besteht, liegt die Vermutung nahe, dass es in meinem Fall ebenfalls an SQL_CALC_FOUND_ROWS liegt.
    Jedenfalls habe ich SQL_CALC_FOUND_ROWS vorerst rausgenommen. Allerdings dauert mir eine Count-Abfrage ohne die Joins einfach zu lange. Normalerweise liefert die Seite innerhalb 0,7 sec den Inhalt aus, mit dem extra Count-Request dauert es jedoch 1-2 sec.

    Derzeit zeige ich die Seitenzahlen von der aktuellen Seite +1 an, was mir persönlich nicht gefällt, da die User auf diese Weise immer nur eine Seite weiter gehen können.

    Am liebsten würde ich es wie Google machen: Einfach immer 10 Seitenzahlen anzeigen. Und wenn man über das Ende hinausspringt, werden nur die Seitenzahlen angezeigt, die auch wirklich existieren. Allerdings habe ich keine Ahnung wie ich das realisieren soll 🙂

    Gruss
    MKay

Eine Antwort schreiben

Ihre E-Mail-Adresse wird nicht veröffentlicht. Benötigte Felder sind markiert mit *

You may use these HTML tags and attributes: <a href=""> <blockquote cite=""> <pre lang=""> <b> <strong> <i> <em>