Мне нужно написать script, который выведет базу данных PostgreSQL. Там может быть много соединений, но script должен игнорировать это.
Стандартный DROP DATABASE db_name
запрос не работает, когда есть открытые соединения.
Как я могу решить проблему?
Это приведет к удалению существующих соединений, кроме ваших:
Запрос 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
. См. этот список рассылки.
В 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
прямо у пользователей базы данных, прежде чем отключать пользователей, иначе пользователи просто продолжат повторное подключение, и вы никогда не получите возможность сбросить БД. См. этот комментарий и вопрос, с которым он связан, Как отключить всех других пользователей из базы данных.
Если вы просто хотите отключить простаивающих пользователей, см. этот вопрос.
Вы можете убить все соединения перед удалением базы данных с помощью функции pg_terminate_backend(int)
.
Вы можете получить все работающие бэкэнды, используя системный вид pg_stat_activity
Я не совсем уверен, но следующее, вероятно, убьет все сеансы:
select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'doomed_database'
Конечно, вы не можете подключиться к этой базе данных
Я заметил, что 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.
В зависимости от вашей версии 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
.
procpid
на pid
этот фрагмент работает на 9.3.
В командной строке Linux, я бы остановил все процессы postgresql, которые выполняются, связывая эту команду sudo/etc/init.d/postgresql restart
введите команду bg, чтобы проверить, все еще запущены другие процессы postgresql.
а затем dropdb dbname, чтобы удалить базу данных
sudo /etc/init.d/postgresql restart
bg
dropdb dbname
Это работает для меня в командной строке linux
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/questions/3185266/postgresql-temporarily-disable-connections
Я просто перезапустил службу в Ubuntu, чтобы отключить подключенные клиенты.
sudo service postgresql stop
sudo service postgresql start
psql
DROP DATABASE DB_NAME;
В моем случае мне пришлось выполнить команду для удаления всех подключений, включая активное соединение с администратором
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
После этого можно было сбросить базу данных