PostgreSQL-Fehler: canceling statement due to statement timeout
ERROR: canceling statement due to statement timeout
Die Anweisung lief länger, als statement_timeout erlaubt, gemessen in Echtzeit ab dem Moment, in dem der Server sie empfing — einschließlich jeder Zeit, die mit Warten auf Locks verbracht wurde. PostgreSQL brach sie ab und rollte ihre Effekte zurück.
Was dieser Fehler bedeutet
SQLSTATE 57014 (query_canceled) deckt alle Anweisungsabbrüche ab; die Meldung sagt Ihnen, welchen Sie erhalten haben:
due to statement timeout— diese Seite:statement_timeoutabgelaufen.due to user request— jemand hat Strg+C gedrückt oderpg_cancel_backend()aufgerufen.due to lock timeout— eine andere Einstellung (lock_timeout) und ein anderer SQLSTATE (55P03): die Anweisung hat das Warten auf einen Lock aufgegeben.
Die entscheidende Feinheit: statement_timeout zählt auch Lock-Wartezeiten mit. Eine Query, die normalerweise 50 ms dauert, kann in ein 30-s-Timeout laufen, weil sie hinter dem ALTER TABLE von jemandem saß. Bevor Sie die Query "optimieren", finden Sie heraus, in welchem Fall Sie sich befinden.
Häufige Ursachen
- Eine wirklich langsame Query: fehlender Index, ein Plan, der nach Datenwachstum oder veralteten Statistiken gekippt ist, ein unbegrenzter Scan.
- An einem Lock blockiert: die Query war in Ordnung, wartete aber hinter DDL oder einer langen Schreibtransaktion.
- Das Timeout ist niedriger gesetzt, als Sie denken — global in
postgresql.conf, pro Rolle oder Datenbank (ALTER ROLE ... SET statement_timeout), pro Sitzung durch den Treiber/das ORM oder pro Transaktion. Diese überschreiben einander und man verliert leicht den Überblick. - Ein Batch-Job oder eine Migration, die berechtigterweise Minuten braucht, aber unter einem OLTP-großen Timeout läuft.
So diagnostizieren Sie ihn
-- Woher der aktive Wert kommt:
SELECT name, setting, source
FROM pg_settings
WHERE name = 'statement_timeout';
-- Overrides pro Rolle/Datenbank:
SELECT * FROM pg_db_role_setting;
Die abgebrochene Anweisung wird zusammen mit dem Fehler ins Server-Log geschrieben, sodass Sie genau wissen, um welche Query es sich handelte. Trennen Sie dann die beiden Fälle:
- Führen Sie sie mit
EXPLAIN (ANALYZE, BUFFERS)in einem sicheren Kontext aus und schauen Sie, wohin die Zeit geht — fügen Sie das JSON in den EXPLAIN-Visualizer ein und prüfen Sie die langsamsten Knoten und die Warnungen zu Zeilenschätzungen. - Wenn es sich live reproduzieren lässt, prüfen Sie
wait_event_type/wait_eventinpg_stat_activity, während sie läuft:Lockbedeutet, dass es ein Blockierungsproblem ist, kein Query-Geschwindigkeitsproblem.
So beheben Sie ihn
- Langsame Query → beheben Sie die Query oder die Indizierung; das ist die eigentliche Lösung, das Timeout hat es nur zutage gefördert.
- Legitime lange Operation → grenzen Sie die Ausnahme ein, statt den globalen Wert zu erhöhen:
BEGIN; SET LOCAL statement_timeout = '30min'; -- gilt nur für diese Transaktion -- ... Migration oder Report ... COMMIT; - Lock-Wartezeiten → verwenden Sie
lock_timeoutfür DDL, damit es schnell fehlschlägt, statt sich anzustellen (und alle hinter sich zu blockieren), und jagen Sie die lange Transaktion, die den Lock hielt. - Behalten Sie eine vernünftige globale Obergrenze. Ein moderates globales
statement_timeoutist ein Schutz gegen entlaufene Queries; die Antwort auf ein False Positive ist ein eingegrenztes Override, nicht das Abschalten.
