Langsame SQL-Abfragen können die Leistung Ihrer WordPress-Website beeinträchtigen. Manchmal sind langsame Abfragen das Ergebnis schlecht formulierter SQL-Befehle, die nie so hätten ausgeführt werden sollen. Und manchmal waren langsame Abfragen eigentlich einmal schnelle Abfragen – aber mit zunehmendem Alter der Website wurden die Abfragen immer langsamer und konnten mit der wachsenden Datenbank nicht mehr Schritt halten.
Unabhängig davon, wie Ihre SQL-Abfragen langsam geworden sind, werfen wir einen Blick auf einige Möglichkeiten, problematische Abfragen in WordPress zu finden und zu beheben.
Langsame Abfragen finden
Das Finden der Quelle langsamer Abfragen besteht aus 2 Schritten
- Identifizieren, welche Abfragen tatsächlich die langsamen sind.
- Finden des Codes, der sie generiert und ausführt.
Schauen wir uns zwei Plugins und einen SaaS an, die uns bei der Suche nach langsamen Abfragen helfen können.
Query Monitor
Query Monitor ist ein Plugin, das *jede Menge* Informationen über die aktuelle Seite liefert. Neben einer ganzen Reihe von Informationen über die internen Abläufe von WordPress bietet es eine detaillierte Aufschlüsselung von
- Wie viele Abfragen bei dieser Anfrage stattgefunden haben
- Welche Abfragen auf der Seite am längsten gedauert haben
- Welche Funktionen die meiste Zeit mit SQL-Abfragen verbracht haben
- Ob diese Abfragen von Plugins, Themes oder dem WordPress-Kern stammten

Query Monitor identifiziert sogar langsame Abfragen mit beängstigend roten Texten, was es super einfach macht, die problematische SQL herauszufiltern.

Debug Bar
Ein weiteres hervorragendes Werkzeug zum Auffinden von quälend langsamer SQL ist das alte, bewährte Debug Bar Plugin. Debug Bar liefert Ihnen Informationen über die internen Abläufe von WordPress, wenn Sie eine Seite laden, mit Dingen wie
- WP_Query-Parameter
- Anfrageinformationen (einschließlich des Abgleichs von Rewrite-Regeln)
- Von der aktuellen Seite generierte SQL-Abfragen
Um Punkt 3 (SQL-Tracking) in Debug Bar zu aktivieren, stellen Sie sicher, dass SAVEQUERIES irgendwo auf Ihrer Website aktiviert ist – wahrscheinlich in wp-config.php – wie folgt:
if ( ! defined( 'SAVEQUERIES' ) ) {
define( 'SAVEQUERIES', true );
}
Warnung: SAVEQUERIES hat Auswirkungen auf die Leistung Ihrer Website und sollte wahrscheinlich nicht auf einem Produktionsserver verwendet werden. Verwenden Sie es stattdessen auf einer Entwicklungsumgebung.
Das Finden langsamer SQL ist mit Debug Bar nicht ganz einfach. Zum Beispiel liefert es keine sortierbaren Tabellen oder hebt langsame Abfragen für Sie hervor. Was Debug Bar jedoch bietet, ist ein Funktions-Trace, der Sie *genau* dorthin führt, wo Sie die Quelle einer Abfrage finden.

Dies ist eine Liste der geladenen Dateien und der Funktionen, die zur Ausführung der Abfrage führen. Meistens interessiert man sich für den letzten Eintrag in der Liste; hier wurde die langsame Abfrage ausgeführt und hier sollten Sie Ihre Suche beginnen. Das Praktische daran, den Kontext jeder einzelnen Funktion zu haben, die zu dieser Abfrage führt, ist, dass sie Aufschluss darüber geben kann, warum die SQL überhaupt ausgeführt wurde.
NewRelic
NewRelic ist ein Dienst, der die Leistung Ihrer Web-App, einschließlich WordPress, misst und überwacht. Der Dienst liefert *eine Tonne* Informationen über die Leistung Ihrer Website. Es ist leicht, sich in den Daten zu verlieren, die NewRelic liefert, von detaillierter Codeausführung bis hin zu zeilenweisen Aufschlüsselungen für SQL-Abfragen.

Es gibt zwei Hauptunterschiede zwischen NewRelic und den zuvor erwähnten Plugins
- NewRelic liefert viel mehr Details über die Leistung Ihres PHP, bis hin zur Anzahl der Millisekunden, die in jeder Funktion verbracht werden
- NewRelic verfolgt jede Anfrage an Ihre Website im Hintergrund, sodass Sie sie später zur Suche nach langsamen SQL-Abfragen heranziehen können. Die Plugins liefern Ihnen nur die aktuelle Seite.
Es ist erwähnenswert, dass NewRelic eine kostenlose Tarifstufe hat, die allgemeine Informationen über die Leistung Ihrer Website liefert, aber Sie müssen auf einen kostenpflichtigen Tarif upgraden, um die Extras für die Überwachung einzelner Anfragen und das Auffinden langsamer Abfragen zu erhalten.
Eine langsame Abfrage mit EXPLAIN verstehen
Bisher haben wir Tools zum Finden langsamer Abfragen behandelt. Lassen Sie uns nun herausfinden, *warum* diese Abfragen die Dinge verlangsamen.
Das MySQL-Schlüsselwort EXPLAIN kann helfen, zu erklären, was passiert. Das Hinzufügen von EXPLAIN am Anfang einer Abfrage zeigt, wie MySQL eine Abfrage ausführt. Bei komplizierten Abfragen kann EXPLAIN helfen, langsame Punkte in Ihren SQLs zu identifizieren, wie z. B. langsame Unterabfragen oder ineffiziente Operationen.
Zum Beispiel, wenn Sie eine Abfrage hätten, die so aussieht:
SELECT slow_column FROM slow_table
Sie könnten diese Abfrage mit folgendem einfach mit EXPLAIN erklären:
EXPLAIN SELECT slow_column FROM slow_table
Hier ist, wie die Ausgabe von EXPLAIN in phpMyAdmin aussieht:

Ich gebe zu, ich verstehe nicht alle internen Abläufe von MySQL, aber das Ausführen von EXPLAIN auf Abfragen liefert dennoch Einblicke, wie MySQL meine SQL ausführt. Verwendet die Abfrage einen Index? Scannt sie die gesamte Tabelle? Selbst bei einfachen Abfragen liefert EXPLAIN einen kleinen Einblick, um zu verstehen, was vor sich geht.
Sie können EXPLAIN von der MySQL-Kommandozeile oder Ihrem bevorzugten MySQL-Tool aus ausführen.
Langsame Abfragen beheben
Nachdem wir nun wissen, dass unsere Abfrage langsam ist und EXPLAIN uns mitgeteilt hat, *warum* sie es ist, schauen wir uns einige Optionen zur Behebung dieser trägen Probleme an.
Option 1: Die Abfrage ändern
Auf CSS-Tricks hatten wir eine Abfrage, die den Bearbeitungsbildschirm für Beiträge auf Schneckentempo verlangsamte. Die Abfrage war Teil der Custom Fields-Metabox. Hier ist die SQL:
SELECT meta_key
FROM wp_postmeta
GROUP BY meta_key
HAVING meta_key NOT LIKE '\\_%'
ORDER BY meta_key
LIMIT 100
Dieser spezielle Teil der SQL-Abfrage ruft eine Liste von meta_keys aus der Tabelle wp_postmeta ab, die nicht mit einem Unterstrich (_) beginnen. Die GROUP BY-Klausel bedeutet, dass jedes Ergebnis eindeutig ist.
Wenn wir diese Abfrage 5 Mal ausführen, hier ist, wie lange sie dauert:
1,7146 Sek.
1,7912 Sek.
1,8077 Sek.
1,7708 Sek.
1,8456 Sek.
Könnten wir eine andere Abfrage schreiben, um dasselbe Ergebnis zu erzielen? Wir müssen *eindeutige* meta_keys auswählen. Eindeutig ist ein Synonym für *distinct*, was zufällig eine SQL-Anweisung ist!
Mit der DISTINCT-Anweisung können wir Folgendes tun:
SELECT DISTINCT meta_key
FROM wp_postmeta
WHERE meta_key NOT LIKE '\\_%'
ORDER BY meta_key
Wenn wir unsere umgeschriebene Abfrage ein paar Mal ausführen, erhalten wir folgende Ergebnisse:
0,3764 Sek.
0,2607 Sek.
0,2661 Sek.
0,2751 Sek.
0,2986 Sek.
Dies ist kaum ein wissenschaftlicher Vergleich, zeigt aber eine deutliche Verbesserung!
Option 2: Einen Index hinzufügen
Wenn Sie eine SQL-Abfrage auf einer Standard-MySQL-Tabelle ausführen, muss MySQL die gesamte Tabelle durchsuchen, um herauszufinden, welche Zeilen für diese spezielle Abfrage relevant sind. Wenn Ihre Tabelle *wirklich groß* wird, dauert dieses Scannen eine ganze Weile.
Dafür sind MySQL-Indizes da. Indizes nehmen die Daten einer Tabelle und organisieren sie so, dass Daten *viel* leichter gefunden werden können. Durch die Organisation der Daten auf eine bestimmte Weise helfen Indizes dabei, die Menge an Scans zu reduzieren, die MySQL für jede Abfrage durchführt.
Indizes können zu einzelnen Spalten oder über mehrere Spalten hinweg hinzugefügt werden. Die Syntax sieht so aus:
CREATE INDEX wp_postmeta_csstricks ON wp_postmeta (meta_key)
Mit einem Index auf meta_key sieht die Zeit der ursprünglichen SQL-Abfrage so aus:
0,0042 Sek.
0,0024 Sek.
0,0031 Sek.
0,0026 Sek.
0,0020 Sek.
Das ist wirklich blitzschnell!
INSERT eine Zeile erstellt oder UPDATE auf einer indizierten Tabelle verwendet wird, wird der Index neu berechnet, was eine kostspielige Operation sein kann. Indizes machen das *Lesen* aus der Tabelle schneller, aber das *Schreiben* in die Tabelle ist langsamer. Ein gut platzierter Index kann Ihre Abfragen beschleunigen, aber übertreiben Sie es nicht mit den Indizes, ohne die Gesamtauswirkungen des Indexes auf Ihre Datenbank zu überwachen.Option 3: Abfrageergebnisse cachen
Wir wissen, dass wir eine langsame Abfrage haben. Anstatt die Abfrage zu ändern, was wäre, wenn wir einfach die *Ergebnisse* der Abfrage speichern würden? Auf diese Weise würden wir begrenzen, wie oft die Abfrage ausgeführt wird, und wir bekämen die meiste Zeit einen „Freifahrtschein“.
Um die Abfrage zu cachen, könnten wir die WordPress Transients API verwenden. Transients werden zum Speichern von Ergebnissen von teuren Operationen verwendet, wie z. B.:
- Anfragen an externe Websites (z. B. Abrufen aktueller Facebook-Posts)
- Langsame Verarbeitungsteile (z. B. Suchen nach großen Zeichenketten mit einem regulären Ausdruck)
- Langsame Datenbankabfragen!
Das Speichern eines Abfrageergebnisses mit Transients sieht ungefähr so aus:
if ( false === ( $results = get_transient( 'transient_key_name' ) ) ) {
$results = ...; // Do the slow query to get the results here
// 60 * 60 is the expiration in seconds - in this case, 3600 seconds (1 hour)
set_transient( 'transient_key_name', $results, 60 * 60 );
}
Das Speichern von Abfrageergebnissen in einem Transient wie diesem bedeutet, dass die Abfrage nur etwa einmal pro Stunde ausgeführt wird. Das führt uns zur *GROSSEN TRANSIENT-WARNUNG*: **Seien Sie vorsichtig mit Transients für Dinge, die sich häufig ändern**.
Wenn Sie eine Abfrage mit Ergebnissen haben, die sich nicht oft ändern, ist die Verwendung von Transients eine raffinierte Möglichkeit, die Datenbank nicht so häufig abfragen zu müssen.
Auswahl eines Ansatzes
Wir haben drei Optionen skizziert, und es gibt wahrscheinlich 17 weitere Möglichkeiten, dieses Problem mit langsamen Abfragen zu lösen. Welchen Ansatz wählen wir?
Wenn ich an Code arbeite, der nicht mein eigener ist, folge ich lieber dem Motto des Programmierers: „Mach das einfachste, was funktionieren kann.“
Option 1 (Neufassung der Abfrage) lieferte hervorragende Ergebnisse, aber was ist, wenn die neu formulierte Abfrage nicht immer die gleichen Ergebnisse liefert? Wir könnten unwissentlich unseren Code mit einer leicht fehlerhaften Abfrage ruinieren.
Option 2 (Hinzufügen eines Indexes) ist nicht immer möglich, abhängig von der Tabelle und den Spalten, die von der Abfrage verwendet werden. Im Fall von WordPress-Core-Tabellen müssten Sie sich Sorgen über Nebenwirkungen von Indizes machen:
- Erwartet die Core-Update-Routine zusätzliche Indizes?
- Verlangsamt das Hinzufügen eines Indexes andere Abfragen, wie z. B.
INSERTundUPDATE?
Option 3 (Caching der Ergebnisse über Transients) hat minimale Auswirkungen – wir ändern die ursprüngliche Abfrage nicht und müssen die Datenbankstruktur nicht ändern.
Meistens verwende ich Option 3. In Ihrem speziellen Fall könnten Sie eine andere Option wählen, abhängig von der Abfrage, die Sie beheben, oder der spezifischen Website, die SQL-Probleme hat. Es gibt keine Einheitslösung für die meisten Leistungsprobleme, daher können Sie meiner Wahl widersprechen oder alle drei gleichzeitig ausprobieren!
Bleiben Sie dran
Wir haben hier ein echtes Problem beschrieben. Die Custom Fields-Box auf CSS-Tricks war tatsächlich ein Übeltäter für einige sehr langsame Datenbankabfragen. Wir haben auch verschiedene Wege zu potenziellen Lösungen skizziert, aber wir haben Ihnen keine tatsächliche codierte Lösung geliefert. Wir werden bald einen zweiten Beitrag dazu veröffentlichen, der Ihnen hoffentlich die Werkzeuge für die Behebung Ihrer eigenen langsamen Abfragen an die Hand gibt, nachdem Sie sie entdeckt haben.
Toller Artikel! Danke.
Großartig! Danke fürs Teilen!
Wenn Transients in der Datenbank gespeichert werden (im Gegensatz zu z. B. APC, Xcache oder Redis), werden abgelaufene Einträge erst entfernt, wenn sie angefordert werden. Wenn Ihre Schlüssel einen gewissen Grad an Einzigartigkeit aufweisen (wie eine Benutzer-ID oder etwas Ähnliches) und nicht häufig aufgerufen werden, kann es zu einer erheblichen Aufblähung in der Datenbank kommen.
Ich habe auch eine dateibasierte Fragment-Caching von Datenbankabfragen verwendet, um die Leistung auf einer Website mit vielen teuren Abfragen zu verbessern. Sie können wp_cache_set() und wp_cache_get() mit Ihrem bevorzugten persistenten Caching-Tool verwenden. Ähnlich wie Transients, aber Sie können sie in einer Datei oder im Speicher behalten, was schneller sein sollte. Sie können die Fragmente mit Benutzer-IDs anpassen, wenn sie für einen bestimmten Benutzer spezifisch sind, wie z. B. eine Liste von Lieblings- oder ungelesenen Beiträgen.
Ich hatte eine Website, bei der einige Seiten mit komplexen Abfragen 3-5 Sekunden dauerten, und konnte dies auf 0,4 – 0,6 Sekunden pro Seite reduzieren. Eine ziemlich riesige Verbesserung des Besuchererlebnisses!
Das ist mein Geheimnis, alle meine Abfragen sind langsam
Schöner Artikel, habe ein paar Dinge gelernt.
Was ist mit der Verwendung von Views und Stored Procedures, um die Leistung von Abfragen zu verbessern?
Das eigentliche Problem ist, dass WordPress keinen Zugriff auf die langsamen Abfrageprotokolle von MySQL hat. Wenn es das könnte, könnte es gemeinsame langsame Abfragen melden, um Rewrites von WordPress-Core vorzuschlagen.
Toller und ausführlicher Artikel mit wunderbarer Anleitung.
Beachten Sie, dass MySQL eine integrierte Funktion für die Protokollierung langsamer Abfragen hat:
https://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html
Möglicherweise verwenden einige der im Artikel erwähnten Tools dies, aber es kann auch ohne zusätzliche Tools erfolgen, nur so zur Information.
Sie könnten eine delete_transient()-Funktion im Hook 'save_post' verwenden, um das Caching von Abfragen zu verhindern, wenn neue Daten verfügbar sind.
Hallo Andy,
Danke für die Tipps. NewRelic hat uns nicht so geholfen, wie es sollte, um unsere Probleme zu lösen, und die Person vom Support, die sich mit unserer Website somproduct.ro beschäftigte, war mehr oder weniger unsichtbar. Nach 12 Tagen beschlossen wir, ihren Service nicht mehr zu nutzen. Unsere Erfahrung war wirklich schlecht, aber wir werden definitiv andere Wege finden müssen, um die hohe Ladezeit zu verhindern und unsere Website zu überwachen.
Myles McNamara meldete sich mit einem spezifischen Abfrageproblem, das für ihn einen großen Unterschied machte.
Ich habe eine Methode gefunden, die die Ladezeit erheblich verkürzt hat (von ca. 14 Sekunden auf ca. 2 Sekunden oder weniger), was auf die Nichtverwendung des meta_key-Indexes in der post_meta-Tabelle zurückzuführen war, siehe hier:
https://core.trac.wordpress.org/ticket/33885
All dies wurde einfach durch Ausführen dieses MySQL-Befehls behoben:
Tom Nowell von Automattic schreibt: