it-swarm-eu.dev

Vynutit pokles db, zatímco ostatní mohou být připojeni

Potřebuji odstranit databázi z clusteru PostgreSQL DB. Jak to mohu udělat, i když existují aktivní připojení? Potřebuji jakýsi příznak -force, Který zruší všechna připojení a poté DB.

Jak to mohu implementovat?

Momentálně používám dropdb, ale jsou možné i jiné nástroje.

126
Alex

V PostgreSQL*, nemůžete zrušit databázi, zatímco klienti jsou k ní připojeni.

Alespoň ne pomocí nástroje dropdb - což je pouze jednoduchý obal kolem DROP DATABASE dotaz na server.

Následuje poměrně robustní řešení:

Připojte se k serveru jako superuživatel pomocí psql nebo jiného klienta. Do nepoužívejte databázi, kterou chcete zrušit.

psql -h localhost postgres postgres

Nyní pomocí běžného databázového klienta můžete vynutit přetažení databáze pomocí tří jednoduchých kroků:

  1. Ujistěte se, že se nikdo nemůže připojit k této databázi. Můžete použít jednu z následujících metod (druhá se zdá bezpečnější, ale nebrání připojení superuživatelů).

    /* 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. Vynutit odpojení všech klientů připojených k této databázi pomocí 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. Přetáhněte databázi.

    DROP DATABASE mydb;
    

Krok 1 vyžaduje oprávnění superuživatele pro 1. metodu a oprávnění vlastníka databáze pro druhý. Krok 2 vyžaduje oprávnění superuživatele . Krok 3 vyžaduje oprávnění vlastníka databáze .


To platí pro všechny verze PostgreSQL, až do verze 12. Verze 13 má DROP DATABASE mydb FORCE


178
filiprem

Použití odpovědi @ filiprem v mém případě a zjednodušení:

-- 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
9
Dorian

Existuje is způsob, jak toho dosáhnout pomocí utilit Shell dropdb & pg_ctl (nebo pg_ctlcluster v Debianu a deriváty). Ale @ filipremova metoda je lepší z několika důvodů:

  • Odpojí pouze uživatele od příslušné databáze.
  • Není třeba restartovat celý cluster.
  • Zabraňuje okamžitému opětovnému připojení, případně zkazí příkaz dropdb.

Cituji man pg_ctlcluster:

S --force používá se „rychlý“ režim, který vrátí zpět všechny aktivní transakce, okamžitě odpojí klienty a tím se čistě vypne. Pokud to nepomůže, dojde k pokusu o vypnutí znovu v „okamžitém“ režimu, který může nechat klastr v nekonzistentním stavu, a tak povede k dalšímu spuštění běhu obnovy. Pokud to stále nepomůže, proces postmistra je zabit. Ukončí s 0 při úspěchu, s 2, pokud server není spuštěn, a s 1 při jiných poruchových stavech. Tento režim by se měl používat pouze tehdy, když se stroj chystá vypnout.

pg_ctlcluster 9.1 main restart --force

nebo

pg_ctl restart -D datadir -m fast

nebo

pg_ctl restart -D datadir -m immediate

okamžitě následuje:

dropdb mydb

Možná ve skriptu pro okamžité nástupnictví.

7

Pokud jste na něco jako RDS, kde připojení bez vybrané databáze vás zavede do databáze, kterou jste ve výchozím nastavení chtěli vytvořit, můžete udělat tuto variantu, abyste se kolem sebe dostali jako poslední otevřené připojení.

 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;
0
Jharwood