Heroku Postgres - hentikan kueri yang digantung (menganggur dalam transaksi)

99

Saya menggunakan Heroku dengan opsi Crane Postgres dan saya menjalankan kueri di database dari mesin lokal saya ketika mesin lokal saya macet. Jika saya lari

select * from pg_stat_activity

salah satu entri memiliki

<IDLE> in transaction

di kolom current_query_text.

Akibatnya, saya tidak bisa menghapus tabel yang sedang ditulis oleh kueri yang dihentikan. Saya telah mencoba menggunakan pg_cancel_backend (N) dan mengembalikan True tetapi sepertinya tidak ada yang terjadi.

Bagaimana cara menghentikan proses ini sehingga saya dapat membatalkan tabel?

alan
sumber
1
Mungkin pertanyaannya harus diubah menjadi "bagaimana cara menghentikan kueri saya sendiri ketika tidak memiliki akses root ke server postgres atau akses superuser ke database". Sepertinya pertanyaan yang sangat bagus memang ... dan saya tidak tahu jawabannya.
tobixen

Jawaban:

138

Ini adalah jawaban Postgres umum, dan tidak khusus untuk heroku


(Jawaban sederhana-bodoh untuk pertanyaan ini mungkin ... mulai ulang postgresql. Dengan asumsi itu tidak diinginkan atau bukan pilihan ...)

Temukan PID dengan menjalankan sql ini:

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

(Permintaan mungkin perlu diperbaiki tergantung dari versi postgres - pada akhirnya, cukup pilih * dari pg_stat_activity). Anda akan menemukan pid di kolom pertama (kiri), dan baris pertama (atas) kemungkinan adalah kueri yang ingin Anda akhiri. Saya akan menganggap pid adalah 1234 di bawah ini.

Anda dapat membatalkan kueri melalui SQL (yaitu tanpa akses shell) selama itu milik Anda atau Anda memiliki akses pengguna super:

select pg_cancel_backend(1234);

Itu adalah permintaan "ramah" untuk membatalkan kueri 1234, dan dengan sedikit keberuntungan itu akan hilang setelah beberapa saat. Akhirnya, ini lebih efisien:

select pg_terminate_backend(1234);

Jika Anda memiliki akses shell dan izin root atau postgres, Anda juga dapat melakukannya dari shell. Untuk "membatalkan" seseorang dapat melakukan:

kill -INT 1234

dan untuk "menghentikan", cukup:

kill 1234

TIDAK:

kill -9 1234

... yang akan sering mengakibatkan seluruh server postgres terbakar, maka Anda juga dapat memulai ulang postgres. Postgres cukup kuat, jadi datanya tidak akan rusak, tetapi saya merekomendasikan untuk tidak menggunakan "kill -9" dalam hal apa pun :-)


"Diam dalam transaksi" yang tahan lama sering kali berarti bahwa transaksi tidak diakhiri dengan "commit" atau "rollback", yang berarti bahwa aplikasi bermasalah atau tidak dirancang dengan benar untuk bekerja dengan database transaksional. "Diam dalam transaksi" yang tahan lama harus dihindari, karena juga dapat menyebabkan masalah kinerja yang besar.

tobixen
sumber
Saya mencoba pg_cancel_backend tetapi tidak berhasil. Saya tidak memiliki akses shell dan saya bukan pengguna super jadi saya tidak dapat mengirim SIGKILL menggunakan pg_terminate_backend
alan
Versi postgres mana yang Anda gunakan? (petunjuk:) select version(). Apakah Anda mendapatkan pesan kesalahan saat menggunakan pg_cancel_backend?
tobixen
Mencoba menggunakan pg_cancel_backend sendiri, jadi mendapat pesan kesalahan "harus menjadi superuser untuk memberi sinyal pada proses server lain" ... artinya tampaknya Anda memerlukan akses root pada server atau akses db melalui beberapa super user postgres (mis. ) untuk menghentikan kueri Anda sendiri. Sepertinya agak menyebalkan :-(
tobixen
1
ternyata proses itu dibatalkan oleh pg_cancel_backend tetapi kueri masih muncul di pg_stat_activity untuk sementara
alan
Mungkin ini khusus untuk Heroku. Sejauh yang saya bisa lihat, di bawah postgres biasa itu benar-benar diperlukan menjadi superuser untuk membunuh proses yang macet (saya menguji dengan "pilih pg_sleep (3600);" pada halaman 8.4, dan saya mendapatkan "ERROR: harus menjadi superuser untuk memberi sinyal proses server lainnya "). Padahal, sekali lagi "menganggur dalam transaksi" tidak persis sama.
tobixen
36

Coba ini:

select pg_terminate_backend(pid int)

Lebih lanjut tentang ini dapat Anda temukan di sini . Ini harus menjadi solusi 'bersih' dari masalah ini daripada membunuh proses demi sistem.

evgenek
sumber
Harap tambahkan cara mendapatkan pid Anda ke jawaban Anda
mountainclimber
19

Anda dapat menginstal heroku-pg-extrasadd-on dan menjalankan perintah berikut untuk mendapatkan PID:

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

Kemudian lakukan saja:

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

CATATAN : --forceopsi dapat digunakan untuk mengeluarkan pg_terminate_backend yang menjatuhkan seluruh koneksi untuk kueri itu.

Jika heroku pg:lockstidak ada daftar apapun, coba heroku pg:ps.

Untuk informasi lebih lanjut, lihat:
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall

davidfrancisco.dll
sumber
Terima kasih. Saya masih tidak dapat menghentikan transaksi / PID ... komputer saya membekukan perangkat keras selama impor dan saya tidak dapat menghentikan PID. :(
dimitarvp
-3

Kita dapat menggunakan yang berikut ini untuk mencapainya dalam satu kueri:

SELECT pg_cancel_backend(pid), pg_terminate_backend(pid) FROM pg_stat_activity WHERE state != 'idle';
codersofthedark
sumber
itu akan mematikan semua kueri yang sedang berjalan, lalu seseorang juga dapat memulai ulang postgres. pesan dengan xact_start dan limit 1, dan saya setuju ... tapi sekali lagi, saya lebih suka melihat daftar sebelum membunuh secara membabi buta.
tobixen
bagaimana dengan ini? SELECT pid, pg_cancel_backend(pid) FROM pg_stat_activity WHERE state != 'idle' AND (now() - query_start) > interval '5 minutes';
AFN