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?
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 .
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 .
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
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
.
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.
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;
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
PostgreSQL 9.2 et supérieur:
SELECT pg_terminate_backend(pid)FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'
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
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