it-swarm.com.de

Wie lösche ich eine PostgreSQL-Datenbank, wenn aktive Verbindungen dazu bestehen?

Ich muss ein Skript schreiben, das eine PostgreSQL-Datenbank löscht. Es mag viele Verbindungen dazu geben, aber das Skript sollte das ignorieren.

Die Standardabfrage DROP DATABASE db_name funktioniert nicht, wenn offene Verbindungen bestehen.

Wie kann ich das Problem lösen?

588

Dadurch werden bestehende Verbindungen außer Ihren getrennt:

Fragen Sie pg_stat_activity ab, und ermitteln Sie die PID-Werte, die Sie beenden möchten. Geben Sie dann SELECT pg_terminate_backend(pid int) an diese Werte aus.

PostgreSQL 9.2 und höher:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
  AND pid <> pg_backend_pid();

PostgreSQL 9.1 und niedriger:

SELECT pg_terminate_backend(pg_stat_activity.procpid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
  AND procpid <> pg_backend_pid();

Sobald Sie die Verbindung zu allen Benutzern getrennt haben, müssen Sie den Befehl DROP DATABASE von einer Verbindung zu einer anderen Datenbank trennen und ausführen, auch wenn Sie nicht versuchen, die Verbindung zu trennen.

Beachten Sie die Umbenennung der Spalte procpid in pid. Siehe dieser Mailinglisten-Thread .

1009
Kuberchaun

Um in PostgreSQL 9.2 und höher alle Verbindungen mit Ausnahme Ihrer Sitzung von der Datenbank zu trennen, mit der Sie verbunden sind, gehen Sie wie folgt vor:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()
  AND pid <> pg_backend_pid();

In älteren Versionen ist es das gleiche, ändern Sie einfach pid in procpid. Um die Verbindung zu einer anderen Datenbank zu trennen, ändern Sie einfach current_database() in den Namen der Datenbank, von der Sie die Verbindung zu Benutzern trennen möchten.

Möglicherweise möchten Sie REVOKE das CONNECT direkt von Benutzern der Datenbank entfernen, bevor Sie die Verbindung zu Benutzern trennen. Andernfalls stellen Benutzer die Verbindung einfach wieder her, und Sie haben nie die Möglichkeit, die Datenbank zu löschen. Siehe dieser Kommentar und die damit verbundene Frage Wie trenne ich alle anderen Benutzer von der Datenbank .

Wenn Sie nur inaktive Benutzer trennen möchten, lesen Sie diese Frage .

115
Craig Ringer

Sie können alle Verbindungen unterbrechen, bevor Sie die Datenbank mit der Funktion pg_terminate_backend(int) löschen.

Sie können alle laufenden Backends über die Systemansicht pg_stat_activity aufrufen.

Ich bin mir nicht ganz sicher, aber das Folgende würde wahrscheinlich alle Sitzungen beenden:

select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'doomed_database'

Natürlich sind Sie möglicherweise nicht selbst mit dieser Datenbank verbunden

26

Abhängig von Ihrer Version von postgresql kann es vorkommen, dass Sie auf einen Fehler stoßen, der dazu führt, dass pg_stat_activity aktive Verbindungen von abgelehnten Benutzern ausschließt. Diese Verbindungen werden auch in pgAdminIII nicht angezeigt.

Wenn Sie automatische Tests durchführen (bei denen Sie auch Benutzer erstellen), ist dies möglicherweise ein wahrscheinliches Szenario.

In diesem Fall müssen Sie auf folgende Abfragen zurückgreifen:

 SELECT pg_terminate_backend(procpid) 
 FROM pg_stat_get_activity(NULL::integer) 
 WHERE datid=(SELECT oid from pg_database where datname = 'your_database');

HINWEIS: Ab Version 9.2 müssen Sie procpid in pid ändern.

17
jb.

Mir ist aufgefallen, dass Postgres 9.2 jetzt die Spalte PID anstatt Procpid aufruft.

Ich neige dazu, es von der Shell zu nennen:

#!/usr/bin/env bash
# kill all connections to the postgres server
if [ -n "$1" ] ; then
  where="where pg_stat_activity.datname = '$1'"
  echo "killing all connections to database '$1'"
else
  echo "killing all connections to database"
fi

cat <<-EOF | psql -U postgres -d postgres 
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
${where}
EOF

Hoffe das ist hilfreich. Vielen Dank an @ JustBob für die SQL.

17
kbrock

Ich starte gerade den Dienst in Ubuntu neu, um verbundene Klienten zu trennen.

Sudo service postgresql stop
Sudo service postgresql start

psql
DROP DATABASE DB_NAME;
13
devdrc

In der Linux-Eingabeaufforderung würde ich zuerst alle laufenden postgresql-Prozesse stoppen, indem ich diesen Befehl binde Sudo /etc/init.d/postgresql restart

geben Sie den Befehl bg ein, um zu überprüfen, ob noch andere postgresql-Prozesse ausgeführt werden

dann gefolgt von dropdb dbname, um die Datenbank zu löschen

Sudo /etc/init.d/postgresql restart
bg
dropdb dbname

Dies funktioniert für mich auf Linux-Eingabeaufforderung

10
Maurice Elagu

PostgreSQL 9.2 und höher:

SELECT pg_terminate_backend(pid)FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'

8
Marcelo C.

Hier ist mein Hack ... = D

# Make sure no one can connect to this database except you!
Sudo -u postgres /usr/pgsql-9.4/bin/psql -c "UPDATE pg_database SET datallowconn=false WHERE datname='<DATABASE_NAME>';"

# Drop all existing connections except for yours!
Sudo -u postgres /usr/pgsql-9.4/bin/psql -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '<DATABASE_NAME>' AND pid <> pg_backend_pid();"

# Drop database! =D
Sudo -u postgres /usr/pgsql-9.4/bin/psql -c "DROP DATABASE <DATABASE_NAME>;"

Ich setze diese Antwort ein, weil ein Befehl (oben) zum Blockieren neuer Verbindungen und weil jeder Versuch mit dem Befehl ...

REVOKE CONNECT ON DATABASE <DATABASE_NAME> FROM PUBLIC, <USERS_ETC>;

... funktioniert nicht, um neue Verbindungen zu blockieren!

Vielen Dank an @araqnid @GoatWalker! = D

https://stackoverflow.com/a/3185413/3223785

7
Eduardo Lucio

In meinem Fall musste ich einen Befehl ausführen, um alle Verbindungen einschließlich meiner aktiven Administratorverbindung zu trennen

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()

das hat alle Verbindungen abgebrochen und mir eine schwerwiegende Fehlermeldung angezeigt:

FATAL: terminating connection due to administrator command SQL state: 57P01

Danach konnte die Datenbank gelöscht werden

0
Chtiwi Malek