Como descartar um banco de dados PostgreSQL se houver conexões ativas?

649

Eu preciso escrever um script que irá soltar um banco de dados PostgreSQL. Pode haver muitas conexões, mas o script deve ignorar isso.

A DROP DATABASE db_nameconsulta padrão não funciona quando há conexões abertas.

Como posso resolver o problema?

Roman Prykhodchenko
fonte
1
Em qual versão do PostgreSQL você está?
Kuberchaun
1
Problema: Embora você possa eliminar as sessões conectadas ao banco de dados, elas podem se reconectar tão rapidamente que você ainda não pode descartar o banco de dados. Felizmente isso mostra Post Como para bloquear novas conexões, para que você possa, em seguida, matar as conexões atuais e soltar o banco de dados de acordo com o plano: dba.stackexchange.com/questions/11893/...
Max Murphy
1
Achei esta resposta no dba.stackexchange muito útil dba.stackexchange.com/a/11895/163539 - sucinta, mas suficientemente explicativa.
hlongmore

Respostas:

1094

Isso eliminará as conexões existentes, exceto a sua:

Consulte pg_stat_activitye obtenha os valores pid que você deseja matar e emita SELECT pg_terminate_backend(pid int)-os.

PostgreSQL 9.2 e superior:

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 e abaixo:

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

Depois de desconectar todos, será necessário desconectar e emitir o comando DROP DATABASE a partir de uma conexão de outro banco de dados, também conhecido como aquele que você não deseja soltar.

Observe a renomeação da procpidcoluna para pid. Veja esta lista de discussão .

Kuberchaun
fonte
11
E, é claro, certifique-se de fazer isso a partir de uma conexão db que não seja uma conexão com 'TARGET_DB', caso contrário, você receberá 'ERROR'. Uma conexão 'postgres' funciona bem.
Rob
3
Na verdade, ele desconectaria os clientes um a um e, se o cliente estiver no meio da lista, ele também será desconectado. Como resultado, algumas conexões permanecerão vivas. Portanto, a resposta certa é de Craig Ringer (veja abaixo). SELECT pg_terminate_backend (pg_stat_activity.pid) FROM pg_stat_activity WHERE nome do dado = current_database () AND pg_stat_activity.pid <> pg_backend_pid ();
Andrew Selivanov
1
Como posso desconectar as conexões após o término da transação atual e, em seguida, descartar as tabelas em questão?
paulkon
5
No meu caso, os clientes se reconectavam rapidamente, portanto, colocar isso um pouco antes ; drop database TARGET_DB;funcionou bem no meu caso para garantir que o banco de dados estivesse ausente no momento em que as coisas começaram a tentar novamente.
Tapete de Schaffer
1
Eu pagaria até dinheiro por um dropdb --force.
Torsten Bronger
125

No PostgreSQL 9.2 e superior, para desconectar tudo, exceto a sua sessão, do banco de dados ao qual você está conectado:

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

Nas versões anteriores é o mesmo, basta mudar pidpara procpid. Para desconectar-se de um banco de dados diferente, mude current_database()para o nome do banco de dados do qual você deseja desconectar os usuários.

Você pode querer REVOKEo CONNECTdireito dos usuários do banco de dados antes de desconectá-los, caso contrário, os usuários continuarão se reconectando e você nunca terá a chance de descartar o banco de dados. Veja este comentário e a pergunta à qual está associado: Como desanexo todos os outros usuários do banco de dados .

Se você deseja apenas desconectar usuários ociosos, consulte esta pergunta .

Craig Ringer
fonte
3
SELECT pg_terminate_backend (pg_stat_activity.pid) FROM pg_stat_activity WHERE nome do dado = current_database () AND pg_stat_activity.pid <> pg_backend_pid ();
Andrew Selivanov 10/10
26

Você pode matar todas as conexões antes de descartar o banco de dados usando a pg_terminate_backend(int)função

Você pode obter todos os back-ends em execução usando a visualização do sistema pg_stat_activity

Não tenho certeza, mas o seguinte provavelmente mataria todas as sessões:

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

Claro que você pode não estar conectado a esse banco de dados

um cavalo sem nome
fonte
19

Dependendo da sua versão do postgresql, você pode encontrar um bug, o que faz pg_stat_activitycom que você omita conexões ativas de usuários descartados. Essas conexões também não são mostradas no pgAdminIII.

Se você estiver realizando testes automáticos (nos quais também cria usuários), esse pode ser um cenário provável.

Nesse caso, você precisa reverter para consultas 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: No 9.2+, você terá que mudar procpidpara pid.

jb.
fonte
1
Isso é o que eu estava procurando, mas (assumindo 9.2 e além), você deve remover a referência a pg_stat_activity e alterar procpid para pid.
MDR
2
Depois de mudar procpidpara pidesse snippet, funciona na 9.3.
jb.
mesmo sem remover o pg_stat_activity? Eu estava recebendo um erro no 9.2
MDR
ESTÁ BEM. Agora eu entendo, isso foi um erro de digitação. Obrigado!
jb.
2
A partir da 9.3 e acima, SELECT pg_terminate_backend (pid) FROM pg_stat_get_activity (NULL :: integer) WHERE datid = (SELECT oid from pg_database where datname = 'your_database');
Shawn Vader
17

Notei que o postgres 9.2 agora chama a coluna pid ao invés de procpid.

Eu costumo chamá-lo da casca:

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

Espero que seja útil. Obrigado a @JustBob pelo sql.

kbrock
fonte
15

Acabei de reiniciar o serviço no Ubuntu para desconectar os clientes conectados.

sudo service postgresql stop
sudo service postgresql start

psql
DROP DATABASE DB_NAME;
devdrc
fonte
10

No prompt de comando do Linux, eu pararia primeiro todos os processos postgresql em execução, vinculando este comando sudo /etc/init.d/postgresql restart

digite o comando bg para verificar se outros processos postgresql ainda estão em execução

seguido por dropdb dbname para descartar o banco de dados

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

Isso funciona para mim no prompt de comando linux

Maurice Elagu
fonte
6
Isso não é bom se você tiver muitos bancos de dados e apenas desejar descartar conexões para um único banco de dados. Isso mataria todas as conexões. É um pouco "marreta-y".
12246 Nick
2
@ Nick verdadeiro, mas lembre-se de que estamos reiniciando todas as conexões e parando-as completamente #
Maurice Elagu 15/02/16
10

PostgreSQL 9.2 e superior:

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

Marcelo C.
fonte
Isso também não encerrará a conexão ativa?
Cocowalla
8

Aqui está o meu hack ... = 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>;"

Eu coloquei esta resposta porque inclui um comando (acima) para bloquear novas conexões e porque qualquer tentativa com o comando ...

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

... não funciona para bloquear novas conexões!

Obrigado a @araqnid @GoatWalker! = D

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

Eduardo Lucio
fonte
5

O próximo PostgreSQL 13 apresentará a FORCEopção.

DROP DATABASE

DROP DATABASE descarta um banco de dados ... Além disso, se alguém estiver conectado ao banco de dados de destino, esse comando falhará, a menos que você use a opção FORCE descrita abaixo.

FORÇA

Tente terminar todas as conexões existentes com o banco de dados de destino. Ele não termina se transações preparadas, slots de replicação lógica ativos ou assinaturas estiverem presentes no banco de dados de destino.

DROP DATABASE db_name WITH (FORCE);
Lukasz Szozda
fonte
0

No meu caso, tive que executar um comando para descartar todas as conexões, incluindo minha conexão de administrador ativo

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

que finalizou todas as conexões e mostra uma mensagem fatal de '' erro '':

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

Depois disso, foi possível descartar o banco de dados

Chtiwi Malek
fonte
0

Nada funcionou para mim, exceto, eu entrei no pgAdmin4 e, no painel, desconectei todas as conexões, exceto o pgAdmin4, e fui capaz de renomear com o botão direito do mouse no banco de dados e nas propriedades e digitei o novo nome.

Ashburn RK
fonte