J'ai besoin de supprimer une base de données d'un cluster de bases de données PostgreSQL. Comment puis-je le faire même s'il y a des connexions actives? J'ai besoin d'une sorte de -force
flag, qui supprimera toutes les connexions, puis la base de données.
Comment puis-je l'implémenter?
J'utilise dropdb
actuellement, mais d'autres outils sont possibles.
Dans PostgreSQL*, vous ne pouvez pas supprimer une base de données pendant que les clients y sont connectés.
Du moins, pas avec l'utilitaire dropdb
- qui n'est qu'un simple wrapper DROP DATABASE
requête du serveur.
Une solution de contournement assez robuste suit:
Connectez-vous à votre serveur en tant que superutilisateur , en utilisant psql
ou un autre client. N'utilisez pas la base de données que vous souhaitez supprimer.
psql -h localhost postgres postgres
Maintenant, en utilisant le client de base de données ordinaire, vous pouvez forcer la suppression de la base de données en trois étapes simples:
Assurez-vous que personne ne peut se connecter à cette base de données. Vous pouvez utiliser l'une des méthodes suivantes (la seconde semble plus sûre, mais n'empêche pas les connexions des superutilisateurs).
/* 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; */
Forcer la déconnexion de tous les clients connectés à cette base de données, à l'aide de 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'; */
Supprimez la base de données.
DROP DATABASE mydb;
L'étape 1 nécessite les privilèges de superutilisateur pour la 1ère méthode et les privilèges du propriétaire de la base de données pour le 2ème. L'étape 2 nécessite les privilèges de superutilisateur . L'étape 3 nécessite le privilège du propriétaire de la base de données .
* Cela s'applique à toutes les versions de PostgreSQL, jusqu'à la version 12. La version 13 a DROP DATABASE mydb FORCE
Utiliser la réponse de @ filiprem dans mon cas et la simplifier:
-- 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
Il y a c'est un moyen de le faire avec les utilitaires Shell dropdb
& pg_ctl
(ou pg_ctlcluster
dans Debian et ses dérivés). Mais méthode @ filiprem est supérieur pour plusieurs raisons:
dropdb
.Je cite man pg_ctlcluster
:
Avec le
--force
option le mode "rapide" est utilisé qui annule toutes les transactions actives, déconnecte immédiatement les clients et s'arrête donc proprement. Si cela ne fonctionne pas, l'arrêt est à nouveau tenté en mode "immédiat", ce qui peut laisser le cluster dans un état incohérent et entraînera ainsi une exécution de la récupération au prochain démarrage. Si cela n'aide toujours pas, le processus du postmaster est interrompu. Quitte avec 0 en cas de succès, avec 2 si le serveur ne fonctionne pas et avec 1 dans les autres conditions d'échec. Ce mode ne doit être utilisé que lorsque la machine est sur le point d'être arrêtée.
pg_ctlcluster 9.1 main restart --force
ou
pg_ctl restart -D datadir -m fast
ou
pg_ctl restart -D datadir -m immediate
immédiatement suivi de:
dropdb mydb
Peut-être dans un script pour une succession immédiate.
Si vous êtes sur quelque chose comme RDS où les connexions sans base de données sélectionnée vous placent dans la base de données que vous avez demandé à créer par défaut, vous pouvez faire cette variante pour contourner le fait d'être la dernière connexion ouverte.
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;