Paksa drop db sementara yang lain mungkin terhubung

104

Saya perlu menghapus database dari klaster DB PostgreSQL. Bagaimana saya bisa melakukannya walaupun ada koneksi aktif? Saya perlu semacam -forcebendera, yang akan menjatuhkan semua koneksi dan kemudian DB.

Bagaimana saya bisa menerapkannya?

Saya menggunakan dropdbsaat ini, tetapi alat lain mungkin.

Alex
sumber

Jawaban:

155

Di PostgreSQL * , Anda tidak bisa menjatuhkan basis data saat klien terhubung dengannya.

Setidaknya, tidak dengan dropdbutilitas - yang hanya merupakan pembungkus sederhana di sekitar DROP DATABASEpermintaan server.

Solusi yang cukup kuat berikut:

Terhubung ke server Anda sebagai pengguna super , menggunakan psqlatau klien lain. Jangan tidak menggunakan database Anda ingin menjatuhkan.

psql -h localhost postgres postgres

Sekarang menggunakan klien database biasa, Anda dapat memaksa drop database menggunakan tiga langkah sederhana:

  1. Pastikan tidak ada yang bisa terhubung ke database ini. Anda dapat menggunakan salah satu metode berikut (yang kedua tampaknya lebih aman, tetapi tidak mencegah koneksi dari pengguna super).

    /* Method 1: update system catalog */
    UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'mydb';
    
    /* Method 2: use ALTER DATABASE. Superusers still can connect!
    ALTER DATABASE mydb CONNECTION LIMIT 0; */
    
  2. Putuskan sambungan semua klien yang terhubung ke database ini, menggunakan pg_terminate_backend.

    SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE datname = 'mydb';
    
    /* For old versions of PostgreSQL (up to 9.1), change pid to procpid:
    
    SELECT pg_terminate_backend(procpid)
    FROM pg_stat_activity
    WHERE datname = 'mydb'; */
    
  3. Jatuhkan basis data.

    DROP DATABASE mydb;

Langkah 1 membutuhkan hak superuser untuk metode pertama, dan hak istimewa pemilik basis data untuk metode kedua. Langkah 2 membutuhkan hak superuser . Langkah 3 membutuhkan hak istimewa pemilik basis data .


* Ini berlaku untuk semua versi PostgreSQL, hingga versi 11.


filiprem
sumber
Jadi saya tidak tahu apa yang saya lakukan salah, tetapi sekarang saya bahkan tidak dapat terhubung ke database yang saya targetkan! Saya juga tidak bisa menjatuhkannya karena tertulis "Pemeliharaan basis data tidak bisa dijatuhkan"
Matt Skeldon
@MattSkeldon, tidak tahu arti pesan ini. Di vanilla PostgreSQL Anda dapat membuang basis data apa pun kecuali template0 & template1. Mungkin Anda menggunakan beberapa versi non-bebas / komersial? Mungkin itu masalah klien bukan masalah server? Apakah Anda mencoba psql?
filiprem
Sayangnya saya berasal dari latar belakang SQL, menggunakan PGSQL digunakan karena status non komersial / gratis.
Matt Skeldon
Ini tidak bekerja untuk saya di mana ada sesi zombie yang sudah berjalan lama. pg_terminate_backend () tidak mematikan sesi-sesi itu, jadi saya masih agak bingung tentang apa yang harus saya lakukan: Saya seorang Postgres su, tetapi saya tidak memiliki akses ke server yang sedang berjalan.
Alexander
6

Ada adalah cara untuk melakukan hal ini dengan utilitas shell dropdb& pg_ctl(atau pg_ctlclusterdi Debian dan turunan). Tetapi metode @ filiprem lebih unggul karena beberapa alasan:

  • Itu hanya memutus pengguna dari database yang dimaksud.
  • Tidak perlu me-restart seluruh cluster.
  • Ini mencegah koneksi ulang segera, mungkin merusak dropdbperintah.

Saya kutip man pg_ctlcluster:

Dengan --forceopsi mode "cepat" digunakan yang memutar kembali semua transaksi aktif, segera memutuskan klien dan dengan demikian dimatikan dengan bersih. Jika itu tidak berhasil, shutdown dicoba lagi dalam mode "langsung", yang dapat membuat cluster dalam keadaan tidak konsisten dan dengan demikian akan mengarah pada pemulihan berjalan di awal berikutnya. Jika ini masih tidak membantu, proses postmaster terbunuh. Keluar dengan 0 pada keberhasilan, dengan 2 jika server tidak berjalan, dan dengan 1 pada kondisi kegagalan lainnya. Mode ini hanya boleh digunakan ketika mesin akan dimatikan.

pg_ctlcluster 9.1 main restart --force

atau

pg_ctl restart -D datadir -m fast

atau

pg_ctl restart -D datadir -m immediate

segera diikuti oleh:

dropdb mydb

Mungkin dalam naskah untuk suksesi segera.

Erwin Brandstetter
sumber
4
Tidak hanya ini kurang dari ideal karena menendang contoh postgres lengkap tetapi tidak dijamin berfungsi. Adalah mungkin bagi klien untuk menghubungkan antara waktu Anda me-restart server dan mencoba menjalankan dropdb lagi. @filiprem jawaban di atas menonaktifkan semua koneksi ke database sebelum memutuskan sambungan dan akan membuat database lain tetap up.
Jim Mitchener
6

Menggunakan jawaban @ filiprem dalam kasus saya dan menyederhanakannya:

-- Connecting to the current user localhost's postgres instance
psql

-- Making sure the database exists
SELECT * from pg_database where datname = 'my_database_name'

-- Disallow new connections
UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'my_database_name';
ALTER DATABASE my_database_name CONNECTION LIMIT 1;

-- Terminate existing connections
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'my_database_name';

-- Drop database
DROP DATABASE my_database_name
Dorian
sumber
0

Jika Anda menggunakan sesuatu seperti RDS di mana koneksi tanpa database yang dipilih menempatkan Anda ke dalam DB yang Anda minta dibuat secara default, Anda dapat melakukan varian ini untuk menjadikan diri Anda sebagai koneksi terbuka terakhir.

 DROP DATABASE IF EXISTS temporary_db_that_shouldnt_exist; 

 CREATE DATABASE temporary_db_that_shouldnt_exist with OWNER your_user; 

 \connect temporary_db_that_shouldnt_exist 
 SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'the_db_you_want_removed'; 


 DROP DATABASE IF EXISTS the_db_you_want_removed; 
 -- 
 -- Name: the_db_you_want_removed; Type: DATABASE; Schema: -; Owner: your_user 
 -- 

 CREATE DATABASE savings_champion WITH TEMPLATE = template0 ENCODING = 'UTF8' LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8'; 


 ALTER DATABASE the_db_you_want_removed OWNER TO your_user; 

 \connect the_db_you_want_removed 

 DROP DATABASE IF EXISTS temporary_db_that_shouldnt_exist;
Jharwood
sumber