2011-03-23 18 views
461

Necesito escribir un script que arroje una base de datos PostgreSQL. Puede haber muchas conexiones, pero el script debe ignorar eso.¿Cómo soltar una base de datos PostgreSQL si hay conexiones activas a ella?

La consulta estándar DROP DATABASE db_name no funciona cuando hay conexiones abiertas.

¿Cómo puedo resolver el problema?

+0

¿En qué versión de PostgreSQL estás? – Kuberchaun

+0

Uso PostgreSQL 8.4 –

+0

Problema: Aunque puede matar las sesiones conectadas a la base de datos, pueden volver a conectarse tan rápido que todavía no puede soltar la base de datos. Afortunadamente, esta publicación muestra cómo bloquear nuevas conexiones, por lo que puede eliminar las conexiones actuales y soltar la base de datos según el plan: http://dba.stackexchange.com/questions/11893/force-drop-db-while-others -may-be-connected –

Respuesta

820

Esto caerá conexiones existentes a excepción de la suya:

de consulta pg_stat_activity y obtener los valores PID se quiere matar, y luego emitir SELECT pg_terminate_backend(pid int) a ellos.

PostgreSQL 9.2 o superior:

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

PostgreSQL 9.1 y abajo:

SELECT pg_terminate_backend(pg_stat_activity.procpid) 
FROM pg_stat_activity 
WHERE pg_stat_activity.datname = 'TARGET_DB' 
    AND procpid <> pg_backend_pid(); 

Una vez desconectado todos los que tendrá que desconectar y emitir el comando DROP DATABASE desde una conexión de otra base de datos, también conocida como la que intentas soltar.

Tenga en cuenta el cambio de nombre de la columna procpid a pid. Ver this mailing list thread.

+2

Funciona desde 8.4 hasta ... – Daniel

+5

Y, por supuesto, asegúrese de hacerlo desde una conexión db que no sea una conexión a 'TARGET_DB', de lo contrario obtendrá 'ERROR'. Una conexión 'postgres' funciona bien. – Rob

+0

Funciona muy bien, solo tiene que recordar que no se puede conectar a este DB. Use Desconectar en la base de datos en pgAdmin. – Konrad

23

Puede matar todas las conexiones antes de abandonar la base de datos utilizando la función pg_terminate_backend(int).

Usted puede obtener todos los backends ejecutan utilizando la vista del sistema pg_stat_activity

No estoy del todo seguro, pero el siguiente, probablemente matar a todas las sesiones:

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

Por supuesto que no esté conectado a sí mismo a esa base de datos

15

Me di cuenta de que postgres 9.2 ahora llama a la columna pid en lugar de procpid.

que tienden a llamar desde el shell:

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

la esperanza de que es útil. Gracias a @JustBob para el sql.

86

En PostgreSQL 9.2 y superiores, para desconectar todo, excepto la sesión de la base de datos que está conectado:

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

En las versiones más antiguas que es lo mismo, sólo cambia pid a procpid. Para desconectarse de una base de datos diferente simplemente cambie current_database() al nombre de la base de datos desde la que desea desconectar a los usuarios.

Es posible que desee REVOKE el CONNECT directamente desde los usuarios de la base de datos antes de desconectar a los usuarios, de lo contrario los usuarios seguirán volviendo a conectarse y nunca tendrán la oportunidad de eliminar la base de datos. Consulte this comment y la pregunta con la que está asociado, How do I detach all other users from the database.

Si solo desea desconectar a los usuarios inactivos, consulte this question.

+2

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

12

Dependiendo de su versión de postgresql, es posible que se encuentre con un error que hace que pg_stat_activity omita las conexiones activas de usuarios caídos. Estas conexiones tampoco se muestran dentro de pgAdminIII.

Si está realizando pruebas automáticas (en las que también crea usuarios), este podría ser un escenario probable.

En este caso es necesario volver a preguntas como:

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

NOTA: En 9.2+ Tendrás cambio procpid a pid.

+0

Ths es lo que estaba buscando, pero para (suponiendo 9.2 y más) tiene que eliminar la referencia a pg_stat_activity y cambiar procpid a pid. – MDR

+2

Después de cambiar '' procpid'' por '' pid'', este fragmento funciona en 9.3. –

+0

incluso sin eliminar pg_stat_activity? Recibí un error en 9.2 – MDR

6

En Linux símbolo del sistema, me gustaría primero detener todos los procesos que se están ejecutando PostgreSQL mediante la vinculación de este comando sudo /etc/init.d/postgresql reiniciar

tipo el comando bg para comprobar si otros procesos PostgreSQL están aún en marcha

continuación, seguido por dbname dropdb dejar caer la base de datos

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

Esto funciona para mí en el comando indicador de Linux

+3

Esto no es bueno si tiene muchas bases de datos y solo desea soltar conexiones para una única base de datos. Esto mataría todas las conexiones. Es un poco "sledge hammer-y". – Nick

+0

@Nick cierto, pero recuerda que estamos reiniciando todas las conexiones y deteniéndolos por completo –

+0

funcionó para mí !!! gracias por una solución simple !! – rikkitikkitumbo

3

PostgreSQL 9.2 o superior:

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

0

En mi caso tuve que ejecutar un mandato para eliminar todas las conexiones entre ellos mi conexión de administrador activa

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

que terminó todas las conexiones y me muestra un error fatal '' '' Mensaje:

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

Después de que era posible dejar caer la base de datos

2

Aquí está mi truco ... = 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>;" 

pongo esta respuesta porque incluir un comando (arriba) para bloquear nuevas conexiones y porque cualquier intento con el comando ...

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

... ¡no funciona para bloquear nuevas conexiones!

¡Gracias a @araqnid @GoatWalker! = D

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

2

acabo de reiniciar el servicio en Ubuntu para desconectar los clientes conectados.

sudo service postgresql stop 
sudo service postgresql start 

psql 
DROP DATABASE DB_NAME; 
Cuestiones relacionadas