Как удалить базу данных PostgreSQL, если есть активные подключения к ней?

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

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

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

Ответ 1

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

Запрос 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'
  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'
  AND procpid <> pg_backend_pid();

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

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

Ответ 2

В 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 прямо у пользователей базы данных, прежде чем отключать пользователей, иначе пользователи просто продолжат повторное подключение, и вы никогда не получите возможность сбросить БД. См. этот комментарий и вопрос, с которым он связан, Как отключить всех других пользователей из базы данных.

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

Ответ 3

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

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

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

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

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

Ответ 4

Я заметил, что 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.

Ответ 5

В зависимости от вашей версии 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.

Ответ 6

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

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

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

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

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

Ответ 7

PostgreSQL 9.2 и выше:

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

Ответ 8

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

fooobar.com/questions/16084/...

Ответ 9

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

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

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

Ответ 10

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

sudo service postgresql stop
sudo service postgresql start

psql
DROP DATABASE DB_NAME;