Forzar caída db mientras otros pueden estar conectados


104

Necesito eliminar una base de datos de un clúster de base de datos PostgreSQL. ¿Cómo puedo hacerlo incluso si hay conexiones activas? Necesito una especie de -forcebandera, que eliminará todas las conexiones y luego la base de datos.

¿Cómo puedo implementarlo?

Estoy usando dropdbactualmente, pero otras herramientas son posibles.

Respuestas:


155

En PostgreSQL * , no puede descartar una base de datos mientras los clientes están conectados a ella.

Al menos, no con la dropdbutilidad, que es solo una simple envoltura alrededor de DROP DATABASEla consulta del servidor.

Una solución bastante sólida sigue:

Conéctese a su servidor como superusuario , utilizando psqlu otro cliente. No , no utilizar la base de datos que desea desconectar.

psql -h localhost postgres postgres

Ahora, utilizando el cliente de base de datos simple, puede forzar la caída de la base de datos mediante tres pasos simples:

  1. Asegúrese de que nadie pueda conectarse a esta base de datos. Puede usar uno de los siguientes métodos (el segundo parece más seguro, pero no impide las conexiones de los superusuarios).

    /* 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. Forzar la desconexión de todos los clientes conectados a esta base de datos, utilizando 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. Descarte la base de datos.

    DROP DATABASE mydb;

El paso 1 requiere privilegios de superusuario para el primer método y privilegios de propietario de la base de datos para el segundo. El paso 2 requiere privilegios de superusuario . El paso 3 requiere privilegio de propietario de la base de datos .


* Esto se aplica a todas las versiones de PostgreSQL, hasta la versión 11.



Así que no sé qué hice mal, ¡pero ahora ni siquiera puedo conectarme a la base de datos a la que apunté! Tampoco puedo soltarlo, ya que dice "La base de datos de mantenimiento no se puede soltar"
Matt Skeldon

@MattSkeldon, no tengo idea de lo que significa este mensaje. En Vanilla PostgreSQL puede eliminar cualquier base de datos, excepto template0 y template1. ¿Quizás usas alguna versión no gratuita / comercial? ¿Quizás es un problema del cliente, no un problema del servidor? ¿Intentaste con psql?
filiprem

Lamentablemente vengo de un fondo SQL, el uso de PGSQL se está utilizando debido al estado no comercial / libre.
Matt Skeldon

Esto no funciona para mí donde hay sesiones de zombies de larga duración. pg_terminate_backend () no mata esas sesiones, así que todavía estoy un poco atascado sobre qué hacer: soy un Postgres su, pero no tengo acceso al servidor en el que se está ejecutando.
Alexander

6

No es una forma de hacer esto con las utilidades de shell dropdby pg_ctl(o pg_ctlclusteren Debian y derivados). Pero el método de @filiprem es superior por varias razones:

  • Solo desconecta a los usuarios de la base de datos en cuestión.
  • No necesita reiniciar todo el clúster.
  • Impide reconexiones inmediatas, posiblemente estropeando el dropdbcomando.

Cito man pg_ctlcluster:

Con la --forceopción, se utiliza el modo "rápido" que revierte todas las transacciones activas, desconecta a los clientes de inmediato y, por lo tanto, se apaga limpiamente. Si eso no funciona, el apagado se intenta nuevamente en modo "inmediato", lo que puede dejar el clúster en un estado inconsistente y, por lo tanto, conducirá a una ejecución de recuperación en el próximo inicio. Si esto todavía no ayuda, el proceso de administrador de correo se cancela. Sale con 0 en caso de éxito, con 2 si el servidor no se está ejecutando y con 1 en otras condiciones de falla. Este modo solo debe usarse cuando la máquina está a punto de apagarse.

pg_ctlcluster 9.1 main restart --force

o

pg_ctl restart -D datadir -m fast

o

pg_ctl restart -D datadir -m immediate

seguido inmediatamente por:

dropdb mydb

Posiblemente en un guión para la sucesión inmediata.


44
Esto no solo es menos que ideal, ya que patea la instancia completa de postgres sino que no se garantiza que funcione. Es posible que un cliente se conecte entre el momento en que reinicia el servidor e intenta ejecutar dropdb nuevamente. La respuesta anterior de @filiprem deshabilita todas las conexiones a la base de datos antes de desconectarse y mantendrá otras bases de datos activas.
Jim Mitchener

6

Usando la respuesta de @filiprem en mi caso y simplificándola:

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

0

Si está en algo como RDS donde las conexiones sin una base de datos seleccionada lo colocan en la base de datos que solicitó que se cree por defecto, puede hacer esta variante para evitar ser la última conexión abierta.

 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;
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.