MySQL Slow Query Log: langsame Abfragen finden
Das Slow Query Log schreibt jede Abfrage mit, die länger als long_query_time braucht — in MySQL und MariaDB
liegt die Vorgabe bei 10 Sekunden, der Minimalwert bei 0, und der Wert darf Dezimalstellen haben. Einschalten
geht im laufenden Betrieb mit SET GLOBAL, auswerten mit mysqldumpslow; wer nichts schreiben will, bekommt
dieselbe Antwort aus performance_schema.events_statements_summary_by_digest. Stand: Oktober 2026, alle Namen
und Vorgabewerte am 22. Oktober 2026 im MySQL-8.4-Referenzhandbuch und in der MariaDB-Serverdokumentation
geprüft.
Einschalten, ohne den Server neu zu starten
Das Protokoll ist laut Handbuch standardmäßig aus. Diese drei Anweisungen schalten es ein, legen die Datei fest und setzen die Schwelle auf eine halbe Sekunde:
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL slow_query_log_file = '/var/log/mysql/mysql-slow.log';
SET GLOBAL long_query_time = 0.5;
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';
Die Falle steckt in der dritten Zeile. long_query_time hat den Gültigkeitsbereich „Global und Session“, und
eine Sitzungsvariable wird beim Verbindungsaufbau aus dem globalen Wert gefüllt. Ihre Konsole, die vor dem
SET GLOBAL schon offen war, arbeitet deshalb weiter mit 10 Sekunden — ein Verbindungspool unter Umständen
stundenlang. Neu verbinden. Und der Dateipfad muss dem Benutzer gehören, unter dem der Server läuft.
Dauerhaft eintragen
SET GLOBAL überlebt keinen Neustart. Dauerhaft gilt nur, was im Abschnitt [mysqld] der Konfigurationsdatei
steht — je nach Paket /etc/mysql/my.cnf oder eine Datei unter /etc/mysql/mysql.conf.d/ beziehungsweise
/etc/mysql/mariadb.conf.d/:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 0.5
min_examined_row_limit = 100
MariaDB: gleiche Funktion, teils andere Namen
MariaDB hat die Variablen ab Version 10.11.0 umbenannt; die alten Namen bleiben als Alias nutzbar, beide Schreibweisen funktionieren also. Dazu kommen drei Schalter, die MySQL nicht hat:
| Zweck | MySQL | MariaDB ab 10.11 | Vorgabe |
|---|---|---|---|
| Protokoll an | slow_query_log |
log_slow_query |
aus |
| Datei | slow_query_log_file |
log_slow_query_file |
host_name-slow.log |
| Schwelle (Sekunden) | long_query_time |
log_slow_query_time |
10.000000 |
| Mindestzahl gelesener Zeilen | min_examined_row_limit |
log_slow_min_examined_row_limit |
0 |
| Detailtiefe | — | log_slow_verbosity |
leer |
| Nur bestimmte Fälle | — | log_slow_filter |
admin,filesort,full_join,full_scan,… |
| Nur jede n-te Abfrage | — | log_slow_rate_limit |
1 |
log_slow_verbosity nimmt unter anderem query_plan, explain und all und schreibt damit den
Ausführungsplan ins Protokoll. Das MySQL-Gegenstück ist log_slow_extra, eingeführt in MySQL 8.0.14 und nur
bei Ausgabe in eine Datei wirksam.
Welche Schwelle sinnvoll ist
Ob eine Abfrage im Protokoll landet, entscheidet der Server laut Handbuch in vier Schritten: keine
Verwaltungsanweisung (oder log_slow_admin_statements ist an), mindestens long_query_time Sekunden gedauert
(oder log_queries_not_using_indexes ist an und es wurde kein Index benutzt), mindestens
min_examined_row_limit Zeilen gelesen, nicht durch log_throttle_queries_not_using_indexes unterdrückt.
Praktisch heißt das: 10 Sekunden sind zu hoch, weil Abfragen, die eine Anwendung ausbremsen, im Bereich von
Zehntelsekunden liegen und erst in der Summe wehtun. 0 schreibt jede Abfrage mit. Auch
log_queries_not_using_indexes ist scharf — das Handbuch warnt, dass das Protokoll damit schnell wächst, weil
jeder harmlose Zugriff auf eine kleine Tabelle hineinläuft: einschalten, zehn Minuten laufen lassen, wieder
ausschalten. Gegen das Rauschen hilft min_examined_row_limit, das in Zeilen zählt und nicht in Sekunden;
alternativ begrenzt log_throttle_queries_not_using_indexes solche Einträge pro Minute, Vorgabe 0 für keine
Begrenzung.
Einen Eintrag lesen
So sieht ein Eintrag aus — nachgebaut nach dem im MySQL-Handbuch dokumentierten Format, nicht aus einer Messung:
# Time: 2026-10-22T08:41:19.372914Z
# User@Host: appuser[appuser] @ localhost [] Id: 214
# Query_time: 4.182553 Lock_time: 0.000128 Rows_sent: 25 Rows_examined: 1842301
SET timestamp=1792658479;
SELECT * FROM bestellungen WHERE kunden_nr = 'K-10428' ORDER BY erstellt_am DESC LIMIT 25;
Vier Felder zählen:
Query_time— Laufzeit der Anweisung in Sekunden.Lock_time— Zeit in Sekunden, die auf Sperren gewartet wurde. Ein hoher Wert hier zeigt auf eine andere Transaktion, nicht auf diese Abfrage.Rows_sent— Zeilen, die an den Client gingen.Rows_examined— Zeilen, die die Serverschicht dafür angesehen hat.
Der wichtigste Satz dieses Beitrags: Nicht Query_time allein verrät den fehlenden Index, sondern das
Verhältnis von Rows_examined zu Rows_sent. Oben stehen 1.842.301 gelesene Zeilen für 25 ausgelieferte —
der Server hat die ganze Tabelle durchgesehen, um 25 Zeilen zu finden. Wie groß sie ist, zeigen die Abfragen
aus Größe von Datenbank und Tabelle
ermitteln. Ist das Verhältnis
eng und Query_time trotzdem hoch, suchen Sie nicht nach einem Index, sondern nach Sperren, Sortierung auf
der Platte oder einem überlasteten Server.
Auswerten statt lesen
Ab ein paar hundert Einträgen liest niemand mehr die Datei. mysqldumpslow liegt den MySQL-Distributionen bei
und verdichtet gleichartige Abfragen zu einer Zeile, indem es Zahlen durch N und Zeichenketten durch 'S'
ersetzt:
# Die zehn Abfragen mit der höchsten Abfragezeit
mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log
# Vorgabe ist -s at, also die durchschnittliche Abfragezeit
mysqldumpslow -s at -t 10 /var/log/mysql/mysql-slow.log
# Nur Abfragen auf eine bestimmte Tabelle
mysqldumpslow -g 'bestellungen' /var/log/mysql/mysql-slow.log
-s t sortiert nach Abfragezeit, -s at nach durchschnittlicher Abfragezeit (die Vorgabe), -t 10 zeigt die
ersten zehn Zeilen, -a schaltet das Zusammenfassen ab. In MariaDB heißt das Werkzeug mariadb-dumpslow und
ist unter Linux per Symlink weiter als mysqldumpslow erreichbar. Mehr zeigt pt-query-digest aus dem Percona
Toolkit: Es liest auch General Log, Binary Log und SHOW PROCESSLIST und gibt je Abfrageklasse Perzentile und
Verteilungen aus statt nur Summen.
Der Weg ohne Protokoll
performance_schema beantwortet dieselbe Frage sofort und ohne Schreiblast. Die Zeitwerte stehen dort in
Pikosekunden, also durch 1.000.000.000.000 teilen, um Sekunden zu erhalten:
SELECT LEFT(DIGEST_TEXT, 100) AS abfrage,
COUNT_STAR AS aufrufe,
ROUND(SUM_TIMER_WAIT / 1000000000000, 3) AS gesamt_s,
ROUND(AVG_TIMER_WAIT / 1000000000000, 4) AS mittel_s,
SUM_ROWS_EXAMINED AS zeilen_gelesen,
SUM_ROWS_SENT AS zeilen_geliefert
FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 10;
Zwei Einschränkungen: Die Tabellen der Performance Schema sind laut Handbuch In-Memory-Tabellen ohne
dauerhaften Speicher, beim Herunterfahren wird ihr Inhalt verworfen — die Auswertung reicht nur bis zum
letzten Serverstart zurück. Und die Zeilenzahl begrenzt performance_schema_digests_size; läuft die Tabelle
über, landet alles Weitere in einer Sammelzeile mit DIGEST = NULL. In MariaDB ist die Performance Schema
zudem standardmäßig aus und nicht im Betrieb einschaltbar — das braucht einen Neustart.
Was danach kommt
Die gefundene Abfrage gehört als Nächstes in ein EXPLAIN, für die tatsächlichen statt der geschätzten
Zeilenzahlen in EXPLAIN ANALYZE — das führt die Anweisung aus und gibt es seit MySQL 8.0.18. In MariaDB
heißt dasselbe Werkzeug ANALYZE <Anweisung> und ergänzt die Spalten r_rows und r_filtered. Vorsicht:
ANALYZE UPDATE und ANALYZE DELETE ändern wirklich Daten.
Aufräumen
Das Protokoll gehört nicht dauerhaft an, schon gar nicht mit einer niedrigen Schwelle:
SET GLOBAL slow_query_log = 'OFF';
FLUSH SLOW LOGS;
FLUSH SLOW LOGS schließt die Protokolldatei und öffnet sie neu — der saubere Weg, nachdem Sie die Datei
weggeschoben oder gelöscht haben. Auf Tabellen hat die Anweisung keine Wirkung: Steht log_output auf TABLE,
schreibt der Server in mysql.slow_log, und diese Tabelle wächst mit. Leeren Sie sie mit
TRUNCATE TABLE mysql.slow_log; oder tauschen Sie sie per RENAME TABLE gegen eine leere Kopie, wenn die
Einträge bleiben sollen. Dass vergessene Protokolle Platten füllen, ist kein Spezialfall — dieselbe Geschichte
erzählen die Binary Logs,
nur in größerem Maßstab.
Wenn eine Anwendung langsam ist und niemand im Haus die Datenbank liest, ist diese Messung unser erster Schritt — wie wir Anwendungen und Datenbanken betreuen, steht unter Webentwicklung.
Quellen
- Slow Query Log, Vorgabewerte (
long_query_time10 Sekunden, Minimum 0, Auflösung Mikrosekunden), Standard-Dateinamehost_name-slow.log, die vier Prüfschritte und die Warnung zulog_queries_not_using_indexes, abgerufen am 22. Oktober 2026: dev.mysql.com/doc/refman/8.4/en/slow-query-log.html - Gültigkeitsbereich der Variablen (
long_query_timeundmin_examined_row_limit: Both,log_slow_extra: Global, alle dynamisch), abgerufen am 22. Oktober 2026: dev.mysql.com — Server System Variable Reference - Sitzungsvariablen werden beim Verbindungsaufbau aus dem globalen Wert gefüllt, abgerufen am 22. Oktober 2026: dev.mysql.com — Using System Variables
log_slow_extraeingeführt in MySQL 8.0.14, abgerufen am 22. Oktober 2026: dev.mysql.com — Variables Added in MySQL 8.0mysqldumpslow: Zusammenfassen zuNund'S', Vorgabe-s at, Schalter-s,-t,-a,-g, abgerufen am 22. Oktober 2026: dev.mysql.com/doc/refman/8.4/en/mysqldumpslow.html- Performance Schema als In-Memory-Tabellen ohne dauerhaften Speicher, abgerufen am 22. Oktober 2026: dev.mysql.com — MySQL Performance Schema
- Zeitwerte der Performance Schema in Pikosekunden, abgerufen am 22. Oktober 2026: dev.mysql.com — Performance Schema Event Timing
events_statements_summary_by_digest, Begrenzung durchperformance_schema_digests_sizeund Sammelzeile mitDIGEST = NULL, abgerufen am 22. Oktober 2026: dev.mysql.com — Statement Summary Tableslog_output,mysql.slow_log, Vorrang vonNONE, Leeren und Tauschen der Protokolltabellen, abgerufen am 22. Oktober 2026: dev.mysql.com — Log Output DestinationsFLUSH SLOW LOGSschließt und öffnet die Protokolldatei, ohne Wirkung auf Protokolltabellen, abgerufen am 22. Oktober 2026: dev.mysql.com/doc/refman/8.4/en/flush.htmlEXPLAIN ANALYZEseit MySQL 8.0.18, abgerufen am 22. Oktober 2026: dev.mysql.com/doc/refman/8.0/en/explain.html- MariaDB: Umbenennung der Slow-Log-Variablen ab 10.11.0, Vorgabewerte,
log_slow_verbosity,log_slow_filter,log_slow_rate_limit, abgerufen am 22. Oktober 2026: mariadb.com — Server System Variables - MariaDB:
mariadb-dumpslow, weiterhin per Symlink alsmysqldumpslowerreichbar, abgerufen am 22. Oktober 2026: mariadb.com — mariadb-dumpslow - MariaDB: Performance Schema standardmäßig aus und nicht im Betrieb aktivierbar, abgerufen am 22. Oktober 2026: mariadb.com — Performance Schema Overview
- MariaDB:
ANALYZE <Anweisung>mitr_rowsundr_filtered, abgerufen am 22. Oktober 2026: mariadb.com — ANALYZE Statement pt-query-digest, Eingabequellen und Ausgabe je Abfrageklasse, abgerufen am 22. Oktober 2026: docs.percona.com/percona-toolkit/pt-query-digest.html
Häufige Fragen
Wie schalte ich das Slow Query Log ohne Neustart ein?
Mit SET GLOBAL slow_query_log = ON, dazu bei Bedarf SET GLOBAL slow_query_log_file und SET GLOBAL long_query_time. Alle drei sind laut Variablenübersicht des MySQL-Handbuchs dynamisch, der Server muss also nicht neu starten. Wichtig: long_query_time hat den Gültigkeitsbereich Global und Session, und eine Sitzungsvariable wird beim Verbindungsaufbau aus dem globalen Wert gefüllt. Ihre schon offene Verbindung arbeitet deshalb weiter mit dem alten Wert — neu verbinden. Nach einem Serverneustart ist die Einstellung wieder weg, dauerhaft gilt nur, was in der Konfigurationsdatei steht.
Wo liegt die Datei mit dem Slow Query Log?
Dort, wo slow_query_log_file hinzeigt: SELECT @@slow_query_log_file; nennt den Pfad. Wenn kein Name gesetzt ist, heißt die Datei laut MySQL-Handbuch host_name-slow.log und der Server legt sie im Datenverzeichnis an, sofern kein absoluter Pfad angegeben wurde. In MariaDB ab 10.11 heißt dieselbe Variable zusätzlich log_slow_query_file. Steht log_output auf TABLE, gibt es keine Datei — dann liegen die Einträge in der Tabelle mysql.slow_log.
Warum bleibt mein Slow Query Log leer?
Vier Ursachen deckt die Prüfreihenfolge im MySQL-Handbuch ab. Erstens ist die Vorgabe von long_query_time 10 Sekunden — so langsam ist kaum eine Abfrage, die eine Anwendung ausbremst. Zweitens muss eine Abfrage mindestens min_examined_row_limit Zeilen gelesen haben. Drittens hat NONE in log_output Vorrang vor jedem anderen Ziel. Viertens behält eine Verbindung, die vor dem SET GLOBAL schon offen war, ihren alten Wert für long_query_time.
Welcher Wert für long_query_time ist sinnvoll?
Die Vorgabe von 10 Sekunden ist in der Praxis zu hoch, der Minimalwert 0 schreibt jede Abfrage mit und lässt die Datei schnell volllaufen. Nehmen Sie als Richtwert die Antwortzeit, die Ihre Anwendung noch verträgt — der Wert wird in Sekunden angegeben und darf Dezimalstellen haben, 0.5 ist also erlaubt. Dann die Größe der Protokolldatei nach einigen Minuten prüfen und den Wert nachziehen. Gegen Rauschen hilft min_examined_row_limit, das in Zeilen zählt, nicht in Sekunden.
Bremst das Slow Query Log den Server?
Jeder Eintrag ist ein Schreibvorgang, bei einer sehr niedrigen Schwelle also messbare Last und eine schnell wachsende Datei. Besonders deutlich wird das mit log_queries_not_using_indexes: das MySQL-Handbuch weist ausdrücklich darauf hin, dass das Protokoll dann schnell wächst, und bietet log_throttle_queries_not_using_indexes als Begrenzung pro Minute an. Wer gar nicht schreiben will, nimmt performance_schema.events_statements_summary_by_digest — dieselbe Frage, ohne Protokolldatei.