Bagaimana cara menjatuhkan basis data PostgreSQL jika ada koneksi aktif?

649

Saya perlu menulis skrip yang akan menjatuhkan database PostgreSQL. Mungkin ada banyak koneksi untuk itu, tetapi skrip harus mengabaikannya.

DROP DATABASE db_nameKueri standar tidak berfungsi ketika ada koneksi terbuka.

Bagaimana saya bisa menyelesaikan masalah?

Roman Prykhodchenko
sumber
1
Versi PostgreSQL apa yang Anda pakai?
Kuberchaun
1
Masalah: Meskipun Anda dapat membunuh sesi yang terhubung ke database, mereka dapat terhubung kembali dengan sangat cepat sehingga Anda masih tidak dapat menjatuhkan database. Untungnya posting ini menunjukkan cara mengunci koneksi baru, sehingga Anda dapat membunuh koneksi saat ini dan drop database sesuai rencana: dba.stackexchange.com/questions/11893/…
Max Murphy
1
Saya menemukan jawaban ini di dba.stackexchange sangat membantu dba.stackexchange.com/a/11895/163539 - ringkas namun cukup jelas.
jauh

Jawaban:

1094

Ini akan menjatuhkan koneksi yang ada kecuali untuk Anda:

Permintaan pg_stat_activitydan dapatkan nilai-nilai pid yang ingin Anda bunuh, kemudian berikan SELECT pg_terminate_backend(pid int)kepada mereka.

PostgreSQL 9.2 dan di atasnya:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
  AND pid <> pg_backend_pid();

PostgreSQL 9.1 dan di bawah ini:

SELECT pg_terminate_backend(pg_stat_activity.procpid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
  AND procpid <> pg_backend_pid();

Setelah Anda memutuskan semua orang, Anda harus memutuskan dan mengeluarkan perintah DROP DATABASE dari koneksi dari database lain alias bukan yang Anda coba jatuhkan.

Perhatikan pengubahan nama procpidkolom menjadi pid. Lihat utas milis ini .

Kuberchaun
sumber
11
Dan tentu saja, pastikan untuk melakukannya dari koneksi db yang bukan koneksi ke 'TARGET_DB', jika tidak Anda akan mendapatkan 'ERROR'. Koneksi 'postgres' berfungsi dengan baik.
Rob
3
Sebenarnya itu akan memutuskan klien satu per satu, dan jika klien Anda ada di tengah daftar itu akan terputus juga. Akibatnya, beberapa koneksi akan tetap hidup. Jadi, jawaban yang benar adalah oleh Craig Ringer (lihat di bawah). SELECT pg_terminate_backend (pg_stat_activity.pid) DARI pg_stat_activity WHERE datname = current_database () DAN pg_stat_activity.pid <> pg_backend_pid ();
Andrew Selivanov
1
Bagaimana saya bisa memutuskan koneksi setelah mereka selesai dengan transaksi mereka saat ini dan kemudian menjatuhkan tabel yang dipertanyakan?
paulkon
5
Dalam kasus saya, klien akan terhubung kembali dengan cepat, jadi menempatkan ini sebelum ; drop database TARGET_DB;bekerja dengan baik dalam kasus saya untuk memastikan db hilang pada saat hal-hal mulai mencoba kembali.
Mat Schaffer
1
Saya bahkan akan membayar uang untuk dropdb --force.
Torsten Bronger
125

Di PostgreSQL 9.2 dan di atasnya, untuk memutuskan segalanya kecuali sesi Anda dari basis data yang terhubung dengan Anda:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()
  AND pid <> pg_backend_pid();

Di versi yang lebih lama itu sama, hanya berubah pidmenjadi procpid. Untuk memutuskan sambungan dari database yang berbeda, cukup ubah current_database()ke nama database yang ingin Anda putuskan pengguna.

Anda mungkin ingin REVOKEyang CONNECTbenar dari pengguna database sebelum memutuskan hubungan pengguna, jika tidak pengguna hanya akan terus menghubungkan kembali dan Anda tidak akan pernah mendapatkan kesempatan untuk menjatuhkan DB. Lihat komentar ini dan pertanyaan yang terkait dengannya, Bagaimana cara melepaskan semua pengguna lain dari basis data .

Jika Anda hanya ingin memutuskan pengguna yang menganggur, lihat pertanyaan ini .

Craig Ringer
sumber
3
SELECT pg_terminate_backend (pg_stat_activity.pid) DARI pg_stat_activity WHERE datname = current_database () DAN pg_stat_activity.pid <> pg_backend_pid ();
Andrew Selivanov
26

Anda bisa mematikan semua koneksi sebelum menjatuhkan basis data menggunakan pg_terminate_backend(int)fungsi.

Anda bisa menjalankan semua backends menggunakan tampilan sistem pg_stat_activity

Saya tidak sepenuhnya yakin, tetapi yang berikut mungkin akan membunuh semua sesi:

select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'doomed_database'

Tentu saja Anda mungkin tidak terhubung sendiri ke database itu

seekor kuda tanpa nama
sumber
19

Bergantung pada versi postgresql Anda, Anda mungkin mengalami bug, yang membuat Anda pg_stat_activitymenghilangkan koneksi aktif dari pengguna yang terputus. Koneksi ini juga tidak ditampilkan di dalam pgAdminIII.

Jika Anda melakukan pengujian otomatis (di mana Anda juga membuat pengguna) ini mungkin skenario yang memungkinkan.

Dalam hal ini, Anda perlu kembali ke kueri seperti:

 SELECT pg_terminate_backend(procpid) 
 FROM pg_stat_get_activity(NULL::integer) 
 WHERE datid=(SELECT oid from pg_database where datname = 'your_database');

CATATAN: Dalam 9.2+ Anda harus mengubahnya procpidke pid.

jb.
sumber
1
Ini adalah apa yang saya cari tetapi untuk (dengan asumsi 9.2 dan seterusnya) Anda harus menghapus referensi ke pg_stat_activity dan mengubah procpid ke pid.
MDR
2
Setelah mengubah procpidke pidsnippet ini berfungsi pada 9.3.
jb.
bahkan tanpa menghapus pg_stat_activity? Saya mendapatkan kesalahan pada 9,2
MDR
BAIK. Sekarang saya mengerti, itu salah ketik. Terima kasih!
jb.
2
Dari 9.3 dan lebih tinggi SELECT pg_terminate_backend (pid) FROM pg_stat_get_activity (NULL :: integer) WHERE datid = (PILIH oid dari pg_database di mana datname = 'your_database');
Shawn Vader
17

Saya perhatikan bahwa postgres 9.2 sekarang memanggil pid kolom daripada procpid.

Saya cenderung menyebutnya dari shell:

#!/usr/bin/env bash
# kill all connections to the postgres server
if [ -n "$1" ] ; then
  where="where pg_stat_activity.datname = '$1'"
  echo "killing all connections to database '$1'"
else
  echo "killing all connections to database"
fi

cat <<-EOF | psql -U postgres -d postgres 
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
${where}
EOF

Semoga bermanfaat. Terima kasih kepada @JustBob untuk sql.

kbrock
sumber
15

Saya baru saja me-restart layanan di Ubuntu untuk memutuskan klien yang terhubung.

sudo service postgresql stop
sudo service postgresql start

psql
DROP DATABASE DB_NAME;
devdrc
sumber
10

Di Prompt perintah Linux, saya akan menghentikan semua proses postgresql yang berjalan dengan mengikat perintah ini sudo /etc/init.d/postgresql restart

ketik perintah bg untuk memeriksa apakah proses postgresql lain masih berjalan

lalu diikuti oleh dropdb dbname untuk drop database

sudo /etc/init.d/postgresql restart
bg
dropdb dbname

Ini berfungsi untuk saya di command prompt linux

Maurice Elagu
sumber
6
Ini tidak baik jika Anda memiliki banyak database dan hanya ingin menjatuhkan koneksi untuk satu DB. Ini akan membunuh semua koneksi. Agak "sledge hammer-y".
Nick
2
@Nick true tapi ingat kita me-restart semua koneksi dan menghentikan mereka sepenuhnya
Maurice Elagu
10

PostgreSQL 9.2 dan di atasnya:

SELECT pg_terminate_backend(pid)FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'

Marcelo C.
sumber
Bukankah itu akan menghentikan koneksi aktif juga?
Cocowalla
8

Ini hack saya ... = D

# Make sure no one can connect to this database except you!
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "UPDATE pg_database SET datallowconn=false WHERE datname='<DATABASE_NAME>';"

# Drop all existing connections except for yours!
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '<DATABASE_NAME>' AND pid <> pg_backend_pid();"

# Drop database! =D
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "DROP DATABASE <DATABASE_NAME>;"

Saya meletakkan jawaban ini karena menyertakan perintah (di atas) untuk memblokir koneksi baru dan karena setiap upaya dengan perintah ...

REVOKE CONNECT ON DATABASE <DATABASE_NAME> FROM PUBLIC, <USERS_ETC>;

... jangan bekerja untuk memblokir koneksi baru!

Terima kasih kepada @araqnid @GoatWalker! = D

https://stackoverflow.com/a/3185413/3223785

Eduardo Lucio
sumber
5

PostgreSQL 13 yang akan datang akan memperkenalkan FORCEopsi.

JATUHKAN DATABASE

DROP DATABASE menjatuhkan basis data ... Juga, jika ada orang lain yang terhubung ke basis data target, perintah ini akan gagal kecuali Anda menggunakan opsi FORCE yang dijelaskan di bawah ini.

MEMAKSA

Mencoba untuk menghentikan semua koneksi yang ada ke database target. Itu tidak berakhir jika transaksi disiapkan, slot replikasi logis aktif atau langganan hadir dalam database target.

DROP DATABASE db_name WITH (FORCE);
Lukasz Szozda
sumber
0

Dalam kasus saya, saya harus menjalankan perintah untuk menjatuhkan semua koneksi termasuk koneksi administrator aktif saya

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()

yang menghentikan semua koneksi dan menunjukkan kepada saya pesan 'kesalahan' fatal:

FATAL: terminating connection due to administrator command SQL state: 57P01

Setelah itu dimungkinkan untuk drop database

Chtiwi Malek
sumber
0

Tidak ada yang bekerja untuk saya kecuali, saya loggin menggunakan pgAdmin4 dan di Dashboard saya memutus semua koneksi kecuali pgAdmin4 dan kemudian dapat mengubah nama dengan menjilat kanan pada database dan properti dan mengetik nama baru.

Ashburn RK
sumber