Force drop db, podczas gdy inne mogą być podłączone

103

Muszę usunąć bazę danych z klastra PostgreSQL DB. Jak mogę to zrobić, nawet jeśli istnieją aktywne połączenia? Potrzebuję coś w rodzaju -forceflagi, która porzuci wszystkie połączenia, a następnie DB.

Jak mogę to zaimplementować?

dropdbObecnie używam , ale inne narzędzia są możliwe.

Alex
źródło

Odpowiedzi:

154

W PostgreSQL * nie można upuścić bazy danych, gdy klienci są z nią połączeni.

Przynajmniej nie z dropdbnarzędziem - które jest tylko prostym otokiem wokół DROP DATABASEzapytania serwera.

Całkiem solidne obejście:

Połącz się z serwerem jako administrator , za pomocą psqllub innego klienta. Czy nie korzystać z bazy danych, którą chcesz upuścić.

psql -h localhost postgres postgres

Teraz za pomocą zwykłego klienta bazy danych możesz wymusić usunięcie bazy danych, wykonując trzy proste kroki:

  1. Upewnij się, że nikt nie może połączyć się z tą bazą danych. Możesz użyć jednej z następujących metod (druga wydaje się bezpieczniejsza, ale nie uniemożliwia połączeń z superużytkownikami).

    /* 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. Wymuś rozłączenie wszystkich klientów podłączonych do tej bazy danych, używając 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. Upuść bazę danych.

    DROP DATABASE mydb;

Krok 1 wymaga uprawnień administratora w przypadku pierwszej metody oraz uprawnień właściciela bazy danych w przypadku drugiej metody. Krok 2 wymaga uprawnień administratora . Krok 3 wymaga uprawnień właściciela bazy danych .


* Dotyczy to wszystkich wersji PostgreSQL, aż do wersji 11.


filiprem
źródło
Więc nie wiem, co zrobiłem źle, ale teraz nie mogę nawet połączyć się z bazą danych, na którą celowałem! Nie mogę też tego upuścić, ponieważ napisano: „Nie można usunąć bazy danych konserwacji”
Matt Skeldon
@MattSkeldon, nie mam pojęcia, co oznacza ta wiadomość. W waniliowym PostgreSQL możesz upuścić dowolną bazę danych oprócz szablonu0 i szablonu1. Może używasz wersji niewolnej / komercyjnej? Może to problem klienta, a nie serwera? Próbowałeś psql?
filiprem
Niestety pochodzę z języka SQL, ponieważ używa się PGSQL ze względu na status niekomercyjny / wolny.
Matt Skeldon
To nie działa dla mnie w przypadku długotrwałych sesji zombie. pg_terminate_backend () nie zabija tych sesji, więc wciąż trochę utknąłem w tym, co robić: jestem su Postgres, ale nie mam dostępu do serwera, na którym on działa.
Alexander
6

Jest na to sposób za pomocą narzędzi powłoki dropdbi pg_ctl(lub pg_ctlclusterw Debianie i pochodnych). Ale metoda @ filiprem jest lepsza z kilku powodów:

  • Odłącza tylko użytkowników od danej bazy danych.
  • Nie trzeba restartować całego klastra.
  • Zapobiega natychmiastowemu ponownemu podłączeniu, prawdopodobnie psując dropdbpolecenie.

Cytuję man pg_ctlcluster:

Z --forceopcją używany jest tryb „szybki”, który wycofuje wszystkie aktywne transakcje, natychmiast rozłącza klientów, a tym samym czyści się automatycznie. Jeśli to nie zadziała, nastąpi próba zamknięcia systemu w trybie „natychmiastowym”, co może pozostawić klaster w niespójnym stanie, a tym samym doprowadzić do uruchomienia odzyskiwania przy następnym uruchomieniu. Jeśli to nadal nie pomaga, proces postmastera zostaje zabity. Wychodzi z 0 w przypadku powodzenia, z 2, jeśli serwer nie działa, i z 1 w innych warunkach awarii. Z tego trybu należy korzystać tylko wtedy, gdy urządzenie ma zostać wyłączone.

pg_ctlcluster 9.1 main restart --force

lub

pg_ctl restart -D datadir -m fast

lub

pg_ctl restart -D datadir -m immediate

natychmiast następuje:

dropdb mydb

Prawdopodobnie w skrypcie do natychmiastowej sukcesji.

Erwin Brandstetter
źródło
4
Nie tylko jest to mniej niż idealne, ponieważ uruchamia pełną instancję postgres, ale nie gwarantuje, że zadziała. Klient może połączyć się między ponownym uruchomieniem serwera a próbą ponownego uruchomienia dropdb. Powyższa odpowiedź @filiprem wyłącza wszystkie połączenia z bazą danych przed rozłączeniem i podtrzymuje działanie innych baz danych.
Jim Mitchener
6

Korzystanie z odpowiedzi @ filiprem w mojej sprawie i uproszczenie jej:

-- 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
dorycki
źródło
0

Jeśli korzystasz z czegoś takiego jak RDS, w którym połączenia bez wybranej bazy danych wprowadzają Cię do DB, o którego utworzenie poprosiłeś, możesz zrobić ten wariant, aby obejść się jako ostatnie otwarte połączenie.

 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
źródło