Как удалить базу данных PostgreSQL, если к ней есть активные подключения? - PullRequest
581 голосов
/ 23 марта 2011

Мне нужно написать скрипт, который будет отбрасывать базу данных PostgreSQL. Может быть много подключений к нему, но скрипт должен игнорировать это.

Стандартный запрос DROP DATABASE db_name не работает при открытых соединениях.

Как мне решить проблему?

Ответы [ 10 ]

1000 голосов
/ 23 марта 2011

Это приведет к удалению существующих подключений, кроме вашего:

Запрос pg_stat_activity и получение значений pid, которые вы хотите убить, а затем выдайте им SELECT pg_terminate_backend(pid int).

PostgreSQL 9.2 и выше:

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 и ниже:

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

Как только вы отключите всех, вам придется отключиться и выполнить команду DROP DATABASE из соединения с другой базой данных, а не той, которую вы пытаетесь удалить.

Обратите внимание на переименование столбца procpid в pid. См. эту ветку списка рассылки .

113 голосов
/ 06 ноября 2012

В PostgreSQL 9.2 и выше отключить все, кроме сеанса, от базы данных, к которой вы подключены:

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

В старых версиях тоже самое, просто измените pid на procpid. Чтобы отключиться от другой базы данных, просто измените current_database() на имя базы данных, от которой вы хотите отключить пользователей.

Возможно, вы захотите REVOKE CONNECT прямо от пользователей базы данных, прежде чем отключать пользователей, в противном случае пользователи просто продолжат повторное подключение, и у вас никогда не будет возможности удалить БД. См. этот комментарий и вопрос, с которым он связан, Как отсоединить всех других пользователей от базы данных .

Если вы просто хотите отключить незанятых пользователей, см. этот вопрос .

26 голосов
/ 23 марта 2011

Вы можете уничтожить все соединения перед удалением базы данных, используя функцию pg_terminate_backend(int).

Вы можете получить все запущенные бэкэнды, используя системное представление pg_stat_activity

Я не совсем уверен, но следующее, вероятно, убило бы все сессии:

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

Конечно, вы не можете подключиться к этой базе данных самостоятельно

17 голосов
/ 10 ноября 2013

В зависимости от вашей версии postgresql вы можете столкнуться с ошибкой, из-за которой pg_stat_activity пропускает активные соединения от сброшенных пользователей.Эти соединения также не показаны внутри pgAdminIII.

Если вы выполняете автоматическое тестирование (в котором вы также создаете пользователей), это может быть вероятным сценарием.

В этом случае вам необходимо вернуться к таким запросам, как:

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

ПРИМЕЧАНИЕ. В версии 9.2+ вы можете изменить procpid на pid.

17 голосов
/ 23 октября 2012

Я заметил, что postgres 9.2 теперь вызывает pid столбца, а не procpid.

Я склонен называть это из оболочки:

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

Надеюсь, это полезно. Спасибо @JustBob за sql.

12 голосов
/ 13 ноября 2017

Я просто перезапускаю сервис в Ubuntu, чтобы отключить подключенных клиентов.

sudo service postgresql stop
sudo service postgresql start

psql
DROP DATABASE DB_NAME;
10 голосов
/ 19 августа 2015

В командной строке Linux я сначала остановил бы все процессы postgresql, которые выполняются, связав эту команду sudo /etc/init.d/postgresql restart

введите команду bg , чтобы проверить, все ли еще запущены процессы postgresql

, затем dropdb dbname для удаления базы данных

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

Это работает для меня в команде linuxподскажите

8 голосов
/ 22 ноября 2016

PostgreSQL 9.2 и выше:

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

6 голосов
/ 20 июля 2017

Вот мой хак ... = 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>;"

Я поставил этот ответ, потому что включаю команду (см. Выше) для блокировки новых подключений, а потому что любая попытка с командой ...

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

... не работает для блокировки новых подключений!

Спасибо @araqnid @GoatWalker! = D

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

0 голосов
/ 02 марта 2017

В моем случае мне нужно было выполнить команду, чтобы сбросить все соединения, включая активное соединение администратора

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

, который разорвал все соединения и показал мне фатальное сообщение об ошибке:

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

После этого можно было сбросить базу данных

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...