Heroku Postgres - hängende Abfrage beenden (in Transaktion inaktiv)

99

Ich verwende Heroku mit der Option Crane Postgres und habe von meinem lokalen Computer aus eine Abfrage in der Datenbank ausgeführt, als mein lokaler Computer abstürzte. Wenn ich renne

select * from pg_stat_activity

einer der Einträge hat

<IDLE> in transaction

in der Spalte current_query_text.

Daher kann ich die Tabelle, in die die abgebrochene Abfrage geschrieben hat, nicht löschen. Ich habe versucht, pg_cancel_backend (N) zu verwenden, und es gibt True zurück, aber es scheint nichts zu passieren.

Wie kann ich diesen Vorgang beenden, damit ich die Tabelle löschen kann?

Alan
quelle
1
Vielleicht sollte die Frage umformuliert werden in "Wie beende ich meine eigene Abfrage, wenn ich weder Root-Zugriff auf den Postgres-Server noch Superuser-Zugriff auf die Datenbank habe?". Es scheint in der Tat eine sehr gute Frage zu sein ... und ich weiß die Antwort nicht.
Tobixen

Antworten:

138

Dies ist eine allgemeine Antwort von Postgres und nicht spezifisch für Heroku


(Die einfach-dumme Antwort auf diese Frage könnte sein ... einfach postgresql neu starten. Vorausgesetzt, das ist nicht wünschenswert oder keine Option ...)

Finden Sie die PID, indem Sie diese SQL ausführen:

SELECT pid , query, * from pg_stat_activity
  WHERE state != 'idle' ORDER BY xact_start;

(Die Abfrage muss möglicherweise abhängig von der Version von postgres repariert werden. Wählen Sie schließlich einfach * aus pg_stat_activity aus.) Sie finden die PID in der ersten (linken) Spalte, und die erste (obere) Zeile ist wahrscheinlich die Abfrage, die Sie beenden möchten. Ich gehe davon aus, dass die PID unten 1234 ist.

Sie können eine Abfrage über SQL abbrechen (dh ohne Shell-Zugriff), solange es Ihre ist oder Sie Super-User-Zugriff haben:

select pg_cancel_backend(1234);

Das ist eine "freundliche" Anfrage, die 1234-Abfrage abzubrechen, und mit etwas Glück wird sie nach einer Weile verschwinden. Letztendlich ist dies effizienter:

select pg_terminate_backend(1234);

Wenn Sie über Shell-Zugriff und Root- oder Postgres-Berechtigungen verfügen, können Sie dies auch über die Shell tun. Um "abzubrechen", kann man tun:

kill -INT 1234

und einfach zu "beenden":

kill 1234

UNTERLASSEN SIE:

kill -9 1234

... das oft dazu führt, dass der gesamte Postgres-Server in Flammen aufgeht, dann können Sie Postgres auch neu starten. Postgres ist ziemlich robust, so dass die Daten nicht beschädigt werden, aber ich würde auf jeden Fall empfehlen, "kill -9" nicht zu verwenden :-)


Ein lang anhaltender "Leerlauf in der Transaktion" bedeutet häufig, dass die Transaktion nicht mit einem "Commit" oder einem "Rollback" beendet wurde, was bedeutet, dass die Anwendung fehlerhaft oder nicht ordnungsgemäß für die Arbeit mit Transaktionsdatenbanken ausgelegt ist. Ein lang anhaltender "Leerlauf in der Transaktion" sollte vermieden werden, da dies auch zu erheblichen Leistungsproblemen führen kann.

Tobixen
quelle
Ich habe pg_cancel_backend ohne Erfolg versucht. Ich habe keinen Shell-Zugriff und bin kein Superuser, daher kann ich kein SIGKILL mit pg_terminate_backend senden
alan
Welche Version von Postgres verwenden Sie? (Hinweis :) select version(). Erhalten Sie bei der Verwendung Fehlermeldungen pg_cancel_backend?
Tobixen
Ich habe versucht, pg_cancel_backend selbst zu verwenden, daher wurde die Fehlermeldung "Superuser muss sein, um andere Serverprozesse zu signalisieren" angezeigt. Dies bedeutet, dass Sie anscheinend entweder Root-Zugriff auf den Server oder Datenbankzugriff über einen Postgres-Superuser (dh einen Postgres-Benutzer) benötigen ) um deine eigene Abfrage zu beenden. Das scheint ein bisschen zu saugen :-(
Tobixen
1
es stellt sich heraus , dass die Prozesse wurden von pg_cancel_backend abgebrochen werden , aber die Abfragen zeigen nach wie vor in pg_stat_activity eine Zeit lang
alan
Vielleicht ist es spezifisch für Heroku. Soweit ich sehen kann, muss es unter normalen Postgres wirklich ein Superuser sein, um einen festgefahrenen Prozess zu beenden (ich teste mit "select pg_sleep (3600);" auf S. 8.4 und erhalte "ERROR: Muss ein Superuser sein, um zu signalisieren andere Serverprozesse "). Andererseits ist "Leerlauf in Transaktion" nicht ganz dasselbe.
Tobixen
36

Versuche dies:

select pg_terminate_backend(pid int)

Mehr dazu finden Sie hier . Dies sollte eine "sauberere" Lösung dieses Problems sein, als den Prozess pro System zu beenden.

evgenek
quelle
Bitte fügen Sie hinzu, wie Sie Ihre PID zu Ihrer Antwort bekommen
Bergsteiger
19

Sie können das heroku-pg-extrasAdd-On installieren und den folgenden Befehl ausführen, um die PID abzurufen:

heroku pg:locks --app <your-app>

Dann machen Sie einfach:

heroku pg:kill <pid> --app <your-app> 

HINWEIS : Mit dieser --forceOption kann pg_terminate_backend ausgegeben werden, wodurch die gesamte Verbindung für diese Abfrage unterbrochen wird.

Wenn heroku pg:locksnichts aufgelistet ist, versuchen Sie es heroku pg:ps.

Weitere Informationen finden Sie unter:
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall

davidfrancisco
quelle
Danke dir. Ich kann die Transaktion / PID trotzdem nicht beenden ... mein Computer hat während eines Imports ein Hardware-Einfrieren durchgeführt und ich kann die PID nicht beenden. :(
dimitarvp
-3

Wir können Folgendes verwenden, um dies in einer einzelnen Abfrage zu erreichen:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';
codersofthedark
quelle
das würde alle laufenden Abfragen töten, dann kann man auch postgres neu starten. Bestellung nach xact_start und Limit 1, und ich könnte zustimmen ... aber andererseits würde ich es vorziehen, die Liste zu betrachten, bevor ich blind töte.
Tobixen
was ist damit? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN