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

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

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

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

10 ответов


это отбросит существующие соединения, за исключением вашего:

запрос 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 из соединения с другой базой данных, а не той, которую вы пытаетесь падение.

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


в 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 to procpid. Чтобы отключиться от другой базы данных, просто измените current_database() к имени базы данных, из которой вы хотите отключить пользователей.

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

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


ты можешь убить все соединения перед удалением базы данных с помощью


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

Я склонен называть его из командной строки:

#!/usr/bin/env bash
# kill all connections to the postgres server
if [ -n "" ] ; then
  where="where pg_stat_activity.datname = ''"
  echo "killing all connections to database ''"
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.


в зависимости от версии 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 to pid.


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

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

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

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

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


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

sudo service postgresql stop
sudo service postgresql start

psql
DROP DATABASE DB_NAME;

в PostgreSQL 9.2 и выше:

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


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


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

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

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