Forza la caduta di db mentre altri potrebbero essere collegati


104

Devo rimuovere un database da un cluster PostgreSQL DB. Come posso farlo anche se ci sono connessioni attive? Ho bisogno di una specie di -forcebandiera, che lascerà cadere tutte le connessioni e poi il DB.

Come posso implementarlo?

dropdbAttualmente sto usando , ma sono possibili altri strumenti.

Risposte:


155

In PostgreSQL * , non è possibile eliminare un database mentre i client sono connessi ad esso.

Almeno, non con l' dropdbutilità, che è solo un semplice wrapper attorno alla DROP DATABASEquery del server.

Segue una soluzione abbastanza solida:

Connettiti al tuo server come superutente , utilizzando psqlo altro client. Evitare Non utilizzare il database che si desidera eliminare.

psql -h localhost postgres postgres

Ora utilizzando un semplice client per database è possibile forzare il rilascio del database in tre semplici passaggi:

  1. Assicurarsi che nessuno possa connettersi a questo database. È possibile utilizzare uno dei seguenti metodi (il secondo sembra più sicuro, ma non impedisce le connessioni dai superutente).

    /* 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. Forza la disconnessione di tutti i client connessi a questo database, usando 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. Rilascia il database.

    DROP DATABASE mydb;

Il passaggio 1 richiede i privilegi di superutente per il 1o metodo e i privilegi del proprietario del database per il 2o. Il passaggio 2 richiede i privilegi di superutente . Il passaggio 3 richiede il privilegio di proprietario del database .


* Questo vale per tutte le versioni di PostgreSQL, fino alla versione 11.



Quindi non so cosa ho fatto di sbagliato, ma ora non riesco nemmeno a collegarmi al database che ho preso di mira! Né posso rilasciarlo perché dice "Impossibile eliminare il database di manutenzione"
Matt Skeldon,

@MattSkeldon, non ho idea di cosa significhi questo messaggio. In Vanilla PostgreSQL è possibile eliminare qualsiasi database tranne template0 e template1. Forse usi una versione non gratuita / commerciale? Forse è un problema client non un problema server? Hai provato psql?
filiprem,

Sfortunatamente vengo da un background SQL, l'utilizzo di PGSQL viene utilizzato a causa dello stato non commerciale / libero.
Matt Skeldon,

Questo non funziona per me dove ci sono sessioni di zombi di lunga durata. pg_terminate_backend () non uccide quelle sessioni, quindi sono ancora un po 'bloccato su cosa fare: sono un Postgres su, ma non ho accesso al server su cui è in esecuzione.
Alexander

6

C'è un modo per fare questo con le utilità shell dropdb& pg_ctl(o pg_ctlclusterin Debian e derivati). Ma il metodo di @ filiprem è superiore per diversi motivi:

  • Disconnette solo gli utenti dal database in questione.
  • Non è necessario riavviare l'intero cluster.
  • Impedisce riconnessioni immediate, eventualmente rovinando il dropdbcomando.

Cito man pg_ctlcluster:

Con l' --forceopzione viene utilizzata la modalità "veloce" che ripristina tutte le transazioni attive, disconnette immediatamente i client e quindi si arresta in modo pulito. Se ciò non funziona, l'arresto viene riprovato in modalità "immediata", che può lasciare il cluster in uno stato incoerente e quindi portare a una corsa di ripristino al successivo avvio. Se il problema persiste, il processo del postmaster viene interrotto. Esce con 0 in caso di successo, con 2 se il server non è in esecuzione e con 1 in altre condizioni di errore. Questa modalità deve essere utilizzata solo quando la macchina sta per essere spenta.

pg_ctlcluster 9.1 main restart --force

o

pg_ctl restart -D datadir -m fast

o

pg_ctl restart -D datadir -m immediate

immediatamente seguito da:

dropdb mydb

Forse in una sceneggiatura per una successione immediata.


4
Non solo non è l'ideale in quanto dà il via all'intero esempio di postgres, ma non è garantito che funzioni. È possibile che un client si connetta al momento del riavvio del server e tenti di eseguire nuovamente dropdb. La risposta di @filiprem sopra disabilita tutte le connessioni al database prima di disconnettersi e manterrà attivi gli altri database.
Jim Mitchener il

6

Utilizzando la risposta di @ filiprem in un mio caso e semplificandola:

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

0

Se sei su qualcosa come RDS in cui le connessioni senza un database selezionato ti mettono nel DB che hai chiesto di essere creato per impostazione predefinita, puoi fare questa variante per aggirare te stesso essendo l'ultima connessione aperta.

 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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.