Heroku Postgres - termina la query in sospeso (inattivo nella transazione)


99

Sto usando Heroku con l'opzione Crane Postgres e stavo eseguendo una query sul database dalla mia macchina locale quando la mia macchina locale si è bloccata. Se corro

select * from pg_stat_activity

una delle voci ha

<IDLE> in transaction

nella colonna current_query_text.

Di conseguenza, non posso eliminare la tabella in cui è stata scritta la query che è stata terminata. Ho provato a usare pg_cancel_backend (N) e restituisce True ma sembra che non succeda nulla.

Come posso terminare questo processo in modo da poter eliminare la tabella?


1
Forse la domanda dovrebbe essere riformulata in "come faccio a terminare la mia query quando non ho né accesso root al server postgres né accesso superutente al database". Sembra davvero un'ottima domanda ... e non conosco la risposta.
tobixen

Risposte:


138

Questa è una risposta Postgres generale e non specifica per heroku


(La semplice-stupida risposta a questa domanda potrebbe essere ... riavvia semplicemente postgresql. Supponendo che non sia desiderabile o non sia un'opzione ...)

Trova il PID eseguendo questo sql:

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

(Potrebbe essere necessario riparare la query a seconda della versione di postgres - alla fine, basta selezionare * da pg_stat_activity). Troverai il pid nella prima colonna (a sinistra) e la prima riga (in alto) è probabilmente la query che desideri terminare. Presumo che il pid sia 1234 sotto.

Puoi annullare una query tramite SQL (ovvero senza accesso alla shell) fintanto che è tua o hai accesso come super utente:

select pg_cancel_backend(1234);

Questa è una richiesta "amichevole" per cancellare la query 1234, e con un po 'di fortuna scomparirà dopo un po'. Alla fine, questo è più efficiente:

select pg_terminate_backend(1234);

Se hai accesso alla shell e permessi di root o postgres puoi farlo anche dalla shell. Per "cancellare" si può fare:

kill -INT 1234

e per "terminare", semplicemente:

kill 1234

NON:

kill -9 1234

... questo spesso porterà l'intero server postgres ad andare in fiamme, quindi potresti anche riavviare postgres. Postgres è abbastanza robusto, quindi i dati non verranno danneggiati, ma in ogni caso sconsiglio di usare "kill -9" :-)


Un "inattività nella transazione" di lunga durata significa spesso che la transazione non è stata terminata con un "commit" o un "rollback", il che significa che l'applicazione è difettosa o non è progettata correttamente per funzionare con i database transazionali. Dovrebbe essere evitato "inattività nella transazione" di lunga durata, poiché può anche causare gravi problemi di prestazioni.


Ho provato pg_cancel_backend senza alcun risultato. Non ho accesso alla shell e non sono un superutente, quindi non posso inviare un SIGKILL utilizzando pg_terminate_backend
alan

Quale versione di postgres stai usando? (suggerimento:) select version(). Ricevi messaggi di errore durante l'utilizzo pg_cancel_backend?
tobixen

Ho tentato di usare pg_cancel_backend io stesso, quindi ho ricevuto il messaggio di errore "deve essere superutente per segnalare altri processi del server" ... il che significa che apparentemente avrai bisogno dell'accesso root sul server o dell'accesso al db tramite un super utente postgres (cioè utente postgres ) per terminare la tua query. Questo sembra un po 'schifo :-(
tobixen

1
si scopre che i processi sono stati annullati da pg_cancel_backend ma le query vengono ancora visualizzate in pg_stat_activity per un po '
alan

Forse è specifico per Heroku. Per quanto posso vedere, in postgres ordinario è davvero necessario essere superutente per uccidere un processo bloccato (sto testando con "select pg_sleep (3600);" a pag 8.4, e ottengo "ERRORE: deve essere superutente per segnalare altri processi del server "). Tuttavia, di nuovo "inattivo nella transazione" non è proprio la stessa cosa.
tobixen

36

Prova questo:

select pg_terminate_backend(pid int)

Maggiori informazioni su questo possono essere trovate qui . Questa dovrebbe essere una soluzione "più pulita" di questo problema rispetto all'uccisione del processo per sistema.


Aggiungi come ottenere il tuo pid alla tua risposta
alpinista

19

È possibile installare il heroku-pg-extrascomponente aggiuntivo ed eseguire il seguente comando per ottenere il PID:

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

Quindi fai semplicemente:

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

NOTA : l' --forceopzione può essere utilizzata per emettere pg_terminate_backend che interrompe l'intera connessione per quella query.

Se heroku pg:locksnon elenca nulla, prova heroku pg:ps.

Per ulteriori informazioni, visita :
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall


Grazie. Tuttavia, non riesco ancora a terminare la transazione / PID ... il mio computer si è bloccato hardware durante un'importazione e non riesco a terminare il PID. :(
dimitarvp

-3

Possiamo utilizzare quanto segue per ottenerlo in una singola query:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';

questo eliminerebbe tutte le query in esecuzione, quindi si potrebbe anche riavviare postgres. ordina per xact_start e limit 1, e potrei essere d'accordo ... ma poi di nuovo, preferirei guardare l'elenco prima di uccidere alla cieca.
tobixen

che dire di questo? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.