Eine Abfrage (oder Verbindung) in PostgreSQL beenden
Zwei Funktionen, ein Eskalationspfad: pg_cancel_backend(pid) bricht die laufende Abfrage ab und lässt die Verbindung am Leben; pg_terminate_backend(pid) schließt die gesamte Verbindung. Beginnen Sie mit Cancel.
-- 1. Die pid finden (mehr dazu im Guide "show running queries"):
SELECT pid, state, now() - query_start AS runtime, left(query, 100)
FROM pg_stat_activity
WHERE state = 'active'
ORDER BY query_start;
-- 2. Abfrage abbrechen (sanft — die Sitzung bleibt verbunden):
SELECT pg_cancel_backend(12345);
-- 3. Wenn das nicht reicht, die Verbindung schließen:
SELECT pg_terminate_backend(12345);
Welches, wann
| Situation | Verwenden |
|---|---|
| Eine Abfrage ist langsam / blockiert andere, die Session ist ansonsten in Ordnung | pg_cancel_backend |
Session hängt idle in transaction und hält Sperren (nichts läuft, das abgebrochen werden könnte) | pg_terminate_backend — Cancel bewirkt hier nichts: es gibt keine Abfrage zum Abbrechen, es ist die offene Transaktion, die schadet |
| Durchgehende Session, die sich neu verbindet und die Abfrage erneut absetzt | Terminate, dann den Client reparieren — es in einer Schleife zu killen ist keine Strategie |
Beide geben true zurück, wenn das Signal gesendet wurde (keine Garantie, dass die Abfrage sofort starb — Abbruch wird an sicheren Punkten geprüft, sodass eine Abfrage, die in einem nicht unterbrechbaren Kernel-Aufruf feststeckt, einen Moment brauchen kann). Das Opfer erhält SQLSTATE 57014 („canceling statement due to user request") oder, wenn terminiert, sieht sein Client den Verbindungsabbruch.
Massenbereinigung, sorgfältig durchgeführt
-- Alle "idle in transaction"-Sitzungen älter als 10 Minuten beenden:
SELECT pid, pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle in transaction'
AND xact_start < now() - interval '10 minutes';
Führen Sie das SELECT zuerst ohne den pg_terminate_backend-Aufruf aus und lesen Sie die Liste — dann, und erst dann, fügen Sie das Kill hinzu. Für eine dauerhafte Lösung setzen Sie idle_in_transaction_session_timeout, statt dies bei jedem Zwischenfall von Hand auszuführen.
Was man niemals tun sollte
Killen Sie einen PostgreSQL-Backend-Prozess niemals mit kill -9 aus der Shell. Ein per SIGKILL beendetes Backend kann seinen Shared-Memory-Zustand nicht aufräumen, sodass der Postmaster Korruption annehmen muss und den gesamten Cluster neu startet, alle trennt und WAL erneut abspielt. Was wie das Killen einer einzelnen Abfrage aussah, wird zu einem vollständigen Ausfall. Ein einfaches kill <pid> (SIGTERM) entspricht pg_terminate_backend und ist akzeptabel, wenn Sie keine Verbindung bekommen — aber die SQL-Funktionen sind stets vorzuziehen, weil sie nicht den falschen Prozess treffen können.
Berechtigungen: Sie können Ihre eigenen Sessions stets abbrechen/terminieren; für die Sessions anderer Benutzer benötigen Sie Mitgliedschaft in pg_signal_backend (oder Superuser).
