Мені потрібно написати сценарій, який видалить базу даних PostgreSQL. З цим може бути багато підключень, але сценарій повинен це ігнорувати.
Стандартний DROP DATABASE db_name
запит не працює, коли є відкриті з'єднання.
Як я можу вирішити проблему?
Мені потрібно написати сценарій, який видалить базу даних PostgreSQL. З цим може бути багато підключень, але сценарій повинен це ігнорувати.
Стандартний 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' -- ← 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
. Дивіться цю нитку списку розсилки .
; drop database TARGET_DB;
добре попрацювати в моєму випадку, щоб переконатися, що db минув до того часу, коли речі почали повторюватися.
dropdb --force
.
У 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
праві від користувачів бази даних перед відключенням користувачів, в іншому випадку користувачі будуть просто тримати на Reconnecting і ви ніколи не отримаєте шанс знизити БД. Дивіться цей коментар та питання, пов’язане з ним, як я відірвати всіх інших користувачів від бази даних .
Якщо ви просто хочете відключити непрацюючих користувачів, перегляньте це питання .
Ви можете вбити всі з'єднання перед тим, як скинути базу даних за допомогою pg_terminate_backend(int)
функції.
Ви можете отримати всі запущені програмні системи за допомогою подання системи pg_stat_activity
Я не зовсім впевнений, але наступне, мабуть, знищить усі сеанси:
select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'doomed_database'
Звичайно, ви, можливо, не підключите себе до цієї бази даних
Залежно від вашої версії 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.
Я помітив, що postgres 9.2 тепер викликає pid стовпця, а не propid.
Я схильний називати це з оболонки:
#!/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.
У командному рядку Linux я спочатку зупинив би всі процеси postgresql, які виконуються, зав'язавши цю команду sudo /etc/init.d/ перезапустити
введіть команду 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
Майбутній PostgreSQL 13 введе FORCE
варіант.
DROP DATABASE скидає базу даних ... Крім того, якщо хто-небудь інший підключений до цільової бази даних, ця команда не вдасться, якщо ви не використовуєте параметр FORCE, описаний нижче.
СИЛА
Спроба припинити всі існуючі підключення до цільової бази даних. Він не припиняється, якщо в цільовій базі даних є підготовлені транзакції, активні слоти логічної реплікації або підписки.
DROP DATABASE db_name WITH (FORCE);
У моєму випадку мені довелося виконати команду, щоб скасувати всі з'єднання, включаючи моє активне підключення адміністратора
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
Після цього можна було скинути базу даних