Erzwinge Drop db, während andere verbunden sind

103

Ich muss eine Datenbank aus einem PostgreSQL-DB-Cluster entfernen. Wie kann ich das tun, auch wenn aktive Verbindungen bestehen? Ich brauche eine Art -forceFlag, das alle Verbindungen und dann die DB aufhebt.

Wie kann ich das umsetzen?

Ich benutze dropdbderzeit, aber andere Tools sind möglich.

Alex
quelle

Antworten:

154

In PostgreSQL * können Sie eine Datenbank nicht löschen, während Clients mit ihr verbunden sind.

Zumindest nicht mit dem dropdbDienstprogramm - das nur ein einfacher Wrapper für DROP DATABASEServerabfragen ist.

Es folgt eine recht robuste Problemumgehung:

Stellen Sie über oder einen anderen Client eine Verbindung zu Ihrem Server als Superuser herpsql . Verwenden Sie nicht die Datenbank, die Sie löschen möchten.

psql -h localhost postgres postgres

Mit dem normalen Datenbank-Client können Sie jetzt das Löschen der Datenbank in drei einfachen Schritten erzwingen:

  1. Stellen Sie sicher, dass niemand eine Verbindung zu dieser Datenbank herstellen kann. Sie können eine der folgenden Methoden verwenden (die zweite scheint sicherer zu sein, verhindert jedoch nicht die Verbindungen von Superusern).

    /* 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. Erzwingen Sie die Trennung aller mit dieser Datenbank verbundenen Clients mit 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. Löschen Sie die Datenbank.

    DROP DATABASE mydb;

Für Schritt 1 sind Superuser- Berechtigungen für die erste Methode und Datenbankbesitzer- Berechtigungen für die zweite Methode erforderlich . Schritt 2 erfordert Superuser- Berechtigungen. Schritt 3 erfordert die Berechtigung des Datenbankbesitzers .


* Dies gilt für alle Versionen von PostgreSQL bis zur Version 11.


filiprem
quelle
Ich weiß also nicht, was ich falsch gemacht habe, aber jetzt kann ich nicht einmal eine Verbindung zu der Datenbank herstellen, auf die ich abzielte! Ich kann es auch nicht
löschen,
@MattSkeldon, keine Ahnung, was diese Nachricht bedeutet. In Vanille PostgreSQL können Sie jede Datenbank außer template0 und template1 löschen. Vielleicht verwenden Sie eine unfreie / kommerzielle Version? Vielleicht ist es Client-Problem nicht Server-Problem? Hast du psql ausprobiert?
Filiprem
Leider komme ich aus einem SQL-Hintergrund, mit PGSQL wird aufgrund des nicht kommerziellen / kostenlosen Status gearbeitet.
Matt Skeldon
Bei Zombiesitzungen mit langer Laufzeit funktioniert das nicht. pg_terminate_backend () bricht diese Sitzungen nicht ab, daher bin ich immer noch ein bisschen festgefahren: Ich bin ein Postgres-Mitglied, aber ich habe keinen Zugriff auf den Server, auf dem es ausgeführt wird.
Alexander
6

Es gibt eine Möglichkeit, dies mit den Shell-Dienstprogrammen dropdb& pg_ctl(oder pg_ctlclusterin Debian und Derivaten) zu tun . Aber Methode des @ filiprem überlegen ist aus mehreren Gründen:

  • Es werden nur Benutzer von der betreffenden Datenbank getrennt.
  • Es muss nicht der gesamte Cluster neu gestartet werden.
  • Es verhindert das sofortige Wiederherstellen der Verbindung und beeinträchtigt möglicherweise den dropdbBefehl.

Ich zitiere man pg_ctlcluster:

Mit der --forceOption "schnell" werden alle aktiven Transaktionen zurückgesetzt, Clients sofort getrennt und somit sauber heruntergefahren. Wenn dies nicht funktioniert, wird im Sofortmodus erneut versucht, den Cluster herunterzufahren. Dies kann zu einem inkonsistenten Zustand des Clusters führen und führt beim nächsten Start zu einem Wiederherstellungslauf. Wenn dies immer noch nicht hilft, wird der Postmaster-Prozess abgebrochen. Beendet den Vorgang mit 0 bei Erfolg, mit 2, wenn der Server nicht ausgeführt wird, und mit 1 bei anderen Fehlerbedingungen. Dieser Modus sollte nur verwendet werden, wenn die Maschine heruntergefahren werden soll.

pg_ctlcluster 9.1 main restart --force

oder

pg_ctl restart -D datadir -m fast

oder

pg_ctl restart -D datadir -m immediate

unmittelbar gefolgt von:

dropdb mydb

Möglicherweise in einem Skript zur sofortigen Nachfolge.

Erwin Brandstetter
quelle
4
Dies ist nicht nur weniger als ideal, da es die gesamte Postgres-Instanz auslöst, sondern es ist auch nicht garantiert, dass es funktioniert. Ein Client kann zwischen dem Neustart des Servers und dem erneuten Versuch, dropdb auszuführen, eine Verbindung herstellen. Durch die obige Antwort von @filiprem werden alle Verbindungen zur Datenbank vor dem Trennen der Verbindung deaktiviert, und andere Datenbanken bleiben erhalten.
Jim Mitchener
6

Verwendung der Antwort von @ filiprem in einem meiner Fälle und Vereinfachung:

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

Wenn Sie sich in einer RDS-Umgebung befinden, in der Verbindungen ohne ausgewählte Datenbank Sie in die Datenbank versetzen, für die Sie standardmäßig die Erstellung beantragt haben, können Sie diese Variante ausführen, um sich selbst als letzte offene Verbindung zu umgehen.

 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
quelle