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

442

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

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

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

  • 0
    На какой версии PostgreSQL вы работаете?
  • 0
    Я использую PostgreSQL 8.4
Показать ещё 2 комментария
Теги:

10 ответов

741
Лучший ответ

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

Запрос 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
    Работает с 8.4 до ...
  • 7
    И, конечно же, обязательно сделайте это из соединения с БД, которое не является соединением с «TARGET_DB», в противном случае вы получите «ОШИБКУ». Соединение «postgres» работает хорошо.
Показать ещё 9 комментариев
79

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

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

  • 2
    SELECT pg_terminate_backend (pg_stat_activity.pid) FROM pg_stat_activity WHERE datname = current_database () И pg_stat_activity.pid <> pg_backend_pid ();
22

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

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

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

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

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

15

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

11

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

  • 0
    Это то, что я искал, но (при условии 9.2 и выше) вы должны удалить ссылку на pg_stat_activity и изменить procpid на pid.
  • 2
    После изменения procpid на pid этот фрагмент работает на 9.3.
Показать ещё 3 комментария
5

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

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

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

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

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

  • 6
    Это не хорошо, если у вас много баз данных и вы хотите сбросить соединения только для одной БД. Это убило бы все соединения. Это немного "кувалда-у".
  • 2
    @ Ник верно, но помните, что мы перезапускаем все соединения и полностью их прекращаем
Показать ещё 1 комментарий
3

PostgreSQL 9.2 и выше:

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

1

Вот мой хак... = 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/questions/3185266/postgresql-temporarily-disable-connections

0

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

sudo service postgresql stop
sudo service postgresql start

psql
DROP DATABASE DB_NAME;
0

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

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

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню