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_name
consulta padrão não funciona quando há conexões abertas.
Como posso resolver o problema?
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_name
consulta padrão não funciona quando há conexões abertas.
Como posso resolver o problema?
Respostas:
Isso eliminará as conexões existentes, exceto a sua:
Consulte pg_stat_activity
e 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 procpid
coluna para pid
. Veja esta lista de discussão .
; 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.
dropdb --force
.
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 pid
para 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 REVOKE
o CONNECT
direito 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 .
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
Dependendo da sua versão do postgresql, você pode encontrar um bug, o que faz pg_stat_activity
com 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 procpid
para pid
.
procpid
para pid
esse snippet, funciona na 9.3.
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.
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
PostgreSQL 9.2 e superior:
SELECT pg_terminate_backend(pid)FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'
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
O próximo PostgreSQL 13 apresentará a FORCE
opção.
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);
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
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.