web-dev-qa-db-fra.com

Comment supprimer une base de données PostgreSQL s'il y a des connexions actives?

Je dois écrire un script qui supprimera une base de données PostgreSQL. Il peut y avoir beaucoup de connexions à cela, mais le script doit l'ignorer.

La requête standard DROP DATABASE db_name ne fonctionne pas lorsqu'il existe des connexions ouvertes.

Comment puis-je résoudre le problème?

588

Cela supprimera les connexions existantes, à l'exception des vôtres:

Interrogez pg_stat_activity et obtenez les valeurs de pid que vous souhaitez supprimer, puis attribuez-leur SELECT pg_terminate_backend(pid int).

PostgreSQL 9.2 et supérieur:

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 et inférieur:

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();

Une fois que vous avez déconnecté tout le monde, vous devrez vous déconnecter et émettre la commande DROP DATABASE à partir d'une connexion provenant d'une autre base de données, pas celle que vous essayez de supprimer.

Notez le changement de nom de la colonne procpid en pid. Voir ce fil de la liste de diffusion .

1009
Kuberchaun

Dans PostgreSQL 9.2 et versions ultérieures, pour déconnecter tout, sauf votre session, de la base de données à laquelle vous êtes connecté:

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

Dans les versions antérieures, il en va de même, remplacez pid par procpid. Pour vous déconnecter d'une autre base de données, il suffit de remplacer current_database() par le nom de la base de données à partir de laquelle vous souhaitez déconnecter des utilisateurs.

Vous souhaiterez peut-être REVOKE le CONNECT auprès des utilisateurs de la base de données avant de déconnecter des utilisateurs, sinon les utilisateurs continueront simplement à se reconnecter et vous ne pourrez jamais supprimer la base de données. Voir ce commentaire et la question à laquelle il est associé, Comment puis-je détacher tous les autres utilisateurs de la base de données .

Si vous souhaitez simplement déconnecter les utilisateurs inactifs, voir cette question .

115
Craig Ringer

Vous pouvez supprimer toutes les connexions avant de supprimer la base de données à l'aide de la fonction pg_terminate_backend(int).

Vous pouvez obtenir tous les backends en cours d’exécution en utilisant la vue système pg_stat_activity

Je ne suis pas tout à fait sûr, mais ce qui suit tuerait probablement toutes les sessions:

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

Bien sûr, vous ne pouvez pas être connecté vous-même à cette base de données

26

En fonction de votre version de postgresql, vous pourriez rencontrer un bogue qui oblige pg_stat_activity à omettre les connexions actives des utilisateurs supprimés. Ces connexions ne sont pas non plus représentées dans pgAdminIII.

Si vous effectuez des tests automatiques (dans lesquels vous créez également des utilisateurs), cela pourrait être un scénario probable.

Dans ce cas, vous devez revenir à des requêtes telles que:

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

NOTE: Dans les versions 9.2+, vous aurez changé procpid en pid.

17
jb.

J'ai remarqué que postgres 9.2 appelle maintenant la colonne pid plutôt que procpid.

J'ai tendance à l'appeler de la coquille:

#!/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

J'espère que c'est utile. Merci à @JustBob pour le sql.

17
kbrock

Je viens de redémarrer le service dans Ubuntu pour déconnecter les clients connectés.

Sudo service postgresql stop
Sudo service postgresql start

psql
DROP DATABASE DB_NAME;
13
devdrc

Dans l'invite de commande Linux, j'arrête tout d'abord tous les processus postgresql en cours d'exécution en liant cette commande Sudo /etc/init.d/postgresql restart

tapez la commande bg pour vérifier si d'autres processus postgresql sont toujours en cours d'exécution

puis suivi de dropdb nombase pour supprimer la base de données

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

Cela fonctionne pour moi sur l'invite de commande linux

10
Maurice Elagu

PostgreSQL 9.2 et supérieur:

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

8
Marcelo C.

Voici mon bidouillage ... = 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>;"

Je mets cette réponse car inclure une commande (ci-dessus) pour bloquer les nouvelles connexions et parce que toute tentative avec la commande ...

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

... ne fonctionne pas pour bloquer de nouvelles connexions!

Merci à @araqnid @GoatWalker! = D

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

7
Eduardo Lucio

Dans mon cas, j'ai dû exécuter une commande pour supprimer toutes les connexions, y compris ma connexion d'administrateur actif.

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

qui a mis fin à toutes les connexions et me montre un message '' erreur '' fatal:

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

Après cela, il était possible de supprimer la base de données

0
Chtiwi Malek