Heroku Postgres - zakończ zawieszone zapytanie (bezczynne w transakcji)

99

Używam Heroku z opcją Crane Postgres i wykonywałem zapytanie w bazie danych z mojego lokalnego komputera, gdy mój lokalny komputer się zawiesił. Jeśli biegnę

select * from pg_stat_activity

jeden z wpisów ma

<IDLE> in transaction

w kolumnie current_query_text.

W rezultacie nie mogę usunąć tabeli, do której zapisywano zapytanie, które zostało zakończone. Próbowałem użyć pg_cancel_backend (N) i zwraca True, ale wydaje się, że nic się nie dzieje.

Jak mogę zakończyć ten proces, aby móc usunąć tabelę?

alan
źródło
1
Może pytanie powinno zostać przeformułowane na "jak zakończyć własne zapytanie, gdy nie mam ani dostępu roota do serwera postgres, ani superużytkownika do bazy danych". Wydaje się, że to naprawdę dobre pytanie ... i nie znam odpowiedzi.
tobixen

Odpowiedzi:

138

To jest ogólna odpowiedź Postgresa, a nie specyficzna dla heroku


(Prosta-głupia odpowiedź na to pytanie może brzmieć ... po prostu uruchom ponownie postgresql. Zakładając, że jest to niepożądane lub nie wchodzi w grę ...)

Znajdź PID, uruchamiając ten sql:

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

(Zapytanie może wymagać naprawy w zależności od wersji postgres - ostatecznie wystarczy wybrać * z pg_stat_activity). Pid znajdziesz w pierwszej (lewej) kolumnie, a pierwszym (górnym) wierszem prawdopodobnie będzie zapytanie, które chcesz zakończyć. Zakładam, że pid to 1234 poniżej.

Możesz anulować zapytanie przez SQL (tj. Bez dostępu do powłoki), o ile jest twoje lub masz dostęp superużytkownika:

select pg_cancel_backend(1234);

To "przyjacielska" prośba o anulowanie zapytania 1234 i przy odrobinie szczęścia zniknie po chwili. Ostatecznie jest to bardziej wydajne:

select pg_terminate_backend(1234);

Jeśli masz dostęp do powłoki i uprawnienia roota lub postgres, możesz to również zrobić z powłoki. Aby „anulować”, można:

kill -INT 1234

i aby „zakończyć”, po prostu:

kill 1234

NIE RÓB:

kill -9 1234

... co często spowoduje, że cały serwer postgres stanie w płomieniach, wtedy równie dobrze możesz ponownie uruchomić postgres. Postgres jest dość niezawodny, więc dane nie zostaną uszkodzone, ale w każdym przypadku odradzałbym używanie "kill -9" :-)


Długotrwała „bezczynność w transakcji” często oznacza, że ​​transakcja nie została zakończona „zatwierdzeniem” lub „wycofaniem”, co oznacza, że ​​aplikacja zawiera błędy lub nie została prawidłowo zaprojektowana do pracy z transakcyjnymi bazami danych. Należy unikać długotrwałego „bezczynności w transakcji”, ponieważ może to również powodować poważne problemy z wydajnością.

tobixen
źródło
Próbowałem pg_cancel_backend bezskutecznie. Nie mam dostępu do powłoki i nie jestem superużytkownikiem, więc nie mogę wysłać SIGKILLa za pomocą pg_terminate_backend
alan
Której wersji postgres używasz? (podpowiedź:) select version(). Czy podczas używania otrzymujesz komunikaty o błędach pg_cancel_backend?
tobixen
Podjąłem próbę użycia pg_cancel_backend samodzielnie, więc otrzymałem komunikat o błędzie "musi być superużytkownikiem, aby zasygnalizować innym procesom serwera" ... co oznacza, że ​​najwyraźniej będziesz potrzebować dostępu roota do serwera lub dostępu do bazy danych przez jakiegoś superużytkownika postgres (tj. Użytkownika postgres ), aby zabić własne zapytanie. To wydaje się trochę do dupy :-(
tobixen
1
okazuje się, że procesy były anulowane przez pg_cancel_backend, ale zapytania nadal są wyświetlane w pg_stat_activity przez chwilę
alan
Być może jest to specyficzne dla Heroku. O ile widzę, w zwykłych postgresach naprawdę trzeba być superużytkownikiem, aby zabić zablokowany proces (testuję z "select pg_sleep (3600);" na stronie 8.4 i otrzymuję "ERROR: must be superuser to signal inne procesy serwera ”). Chociaż z drugiej strony „bezczynność w transakcji” to nie to samo.
tobixen
36

Spróbuj tego:

select pg_terminate_backend(pid int)

Więcej na ten temat można znaleźć tutaj . Powinno to być „czystsze” rozwiązanie tego problemu niż zabijanie procesu przez system.

evgenek
źródło
Dodaj, jak dodać swój pid do odpowiedzi
alpinista
19

Możesz zainstalować heroku-pg-extrasdodatek i uruchomić następujące polecenie, aby uzyskać identyfikator PID:

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

Następnie po prostu wykonaj:

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

UWAGA : --forceopcja może być użyta do wydania pg_terminate_backend, który przerywa całe połączenie dla tego zapytania.

Jeśli heroku pg:locksnic nie wymienia, spróbuj heroku pg:ps.

Więcej informacji można znaleźć pod adresem :
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall

davidfrancisco
źródło
Dziękuję Ci. Jednak nadal nie mogę zakończyć transakcji / PID ... mój komputer zawiesił się sprzętowo podczas importu i nie mogę zakończyć PID. :(
dimitarvp
-3

Aby to osiągnąć w jednym zapytaniu, możemy użyć następujących czynności:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';
codersofthedark
źródło
który zabiłby wszystkie uruchomione zapytania, a następnie równie dobrze można zrestartować postgres. order by xact_start i limit 1, i mógłbym się zgodzić ... ale z drugiej strony wolałbym spojrzeć na listę przed zabiciem na ślepo.
tobixen
a co z tym? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN