Muszę napisać skrypt, który upuści bazę danych PostgreSQL. Może być z nim wiele połączeń, ale skrypt powinien to zignorować.
Standardowe DROP DATABASE db_name
zapytanie nie działa, gdy istnieją otwarte połączenia.
Jak mogę rozwiązać problem?
Muszę napisać skrypt, który upuści bazę danych PostgreSQL. Może być z nim wiele połączeń, ale skrypt powinien to zignorować.
Standardowe DROP DATABASE db_name
zapytanie nie działa, gdy istnieją otwarte połączenia.
Jak mogę rozwiązać problem?
Odpowiedzi:
Spowoduje to porzucenie istniejących połączeń oprócz twoich:
Zapytaj pg_stat_activity
i uzyskaj wartości pid, które chcesz zabić, a następnie wydaj SELECT pg_terminate_backend(pid int)
je.
PostgreSQL 9.2 i nowsze wersje:
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 i poniżej:
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();
Gdy rozłączysz wszystkich, będziesz musiał rozłączyć i wydać polecenie DROP DATABASE z połączenia z innej bazy danych, inaczej niż ta, którą próbujesz usunąć.
Zwróć uwagę na zmianę nazwy procpid
kolumny na pid
. Zobacz ten wątek listy adresowej .
; drop database TARGET_DB;
działało dobrze w moim przypadku, aby upewnić się, że baza danych zniknęła, zanim wszystko zacznie się ponawiać.
dropdb --force
.
W PostgreSQL 9.2 i nowszych, aby odłączyć wszystko oprócz sesji od bazy danych, z którą jesteś połączony:
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()
AND pid <> pg_backend_pid();
W starszych wersjach jest tak samo, wystarczy zmienić pid
na procpid
. Aby rozłączyć się z inną bazą danych, wystarczy zmienić current_database()
nazwę bazy danych, z której chcesz rozłączyć użytkowników.
Możesz REVOKE
na CONNECT
prawo od użytkowników bazy danych przed odłączeniem użytkowników, inaczej użytkownicy będą po prostu zachować na ponownym podłączeniu i nigdy nie będziesz miał szansę na wyrzucenie DB. Zobacz ten komentarz i pytanie z nim związane: Jak odłączyć wszystkich innych użytkowników od bazy danych .
Jeśli chcesz tylko odłączyć bezczynnych użytkowników, zobacz to pytanie .
Możesz usunąć wszystkie połączenia przed usunięciem bazy danych za pomocą pg_terminate_backend(int)
funkcji.
Możesz uzyskać wszystkie działające backendy za pomocą widoku systemu pg_stat_activity
Nie jestem do końca pewien, ale następujące działania prawdopodobnie zabiłyby wszystkie sesje:
select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'doomed_database'
Oczywiście możesz nie być podłączony do tej bazy danych
W zależności od wersji postgresql możesz napotkać błąd, który powoduje pg_stat_activity
pominięcie aktywnych połączeń od upuszczonych użytkowników. Te połączenia nie są również pokazane w pgAdminIII.
Jeśli wykonujesz testy automatyczne (w których również tworzysz użytkowników), może to być prawdopodobny scenariusz.
W takim przypadku musisz wrócić do zapytań takich jak:
SELECT pg_terminate_backend(procpid)
FROM pg_stat_get_activity(NULL::integer)
WHERE datid=(SELECT oid from pg_database where datname = 'your_database');
UWAGA: W wersji 9.2+ zmienisz procpid
na pid
.
procpid
na pid
ten fragment działa na 9.3.
Zauważyłem, że postgres 9.2 teraz nazywa kolumnę pid zamiast procpid.
Zwykle nazywam to z powłoki:
#!/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
Mam nadzieję, że jest to pomocne. Dzięki @JustBob dla sql.
W wierszu polecenia systemu Linux najpierw zatrzymałbym wszystkie uruchomione procesy postgresql, wiążąc to polecenie sudo /etc/init.d/postgresql restart
wpisz polecenie bg, aby sprawdzić, czy inne procesy postgresql nadal działają
a następnie dropdb dbname, aby usunąć bazę danych
sudo /etc/init.d/postgresql restart
bg
dropdb dbname
Działa to dla mnie w wierszu poleceń systemu Linux
PostgreSQL 9.2 i nowsze wersje:
SELECT pg_terminate_backend(pid)FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'
Oto mój hack ... = 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>;"
Podaję tę odpowiedź, ponieważ zawierają polecenie (powyżej), aby zablokować nowe połączenia i ponieważ każda próba użycia polecenia ...
REVOKE CONNECT ON DATABASE <DATABASE_NAME> FROM PUBLIC, <USERS_ETC>;
... nie działa, aby blokować nowe połączenia!
Dzięki @araqnid @GoatWalker! = D.
Nadchodzące PostgreSQL 13 wprowadzi FORCE
opcję.
DROP DATABASE upuszcza bazę danych ... Również jeśli ktoś inny jest podłączony do docelowej bazy danych, to polecenie zakończy się niepowodzeniem, chyba że użyjesz opcji FORCE opisanej poniżej.
SIŁA
Próba zakończenia wszystkich istniejących połączeń z docelową bazą danych. Nie kończy się, jeśli w docelowej bazie danych znajdują się przygotowane transakcje, aktywne logiczne gniazda replikacji lub subskrypcje.
DROP DATABASE db_name WITH (FORCE);
W moim przypadku musiałem wykonać polecenie, aby usunąć wszystkie połączenia, w tym moje aktywne połączenie administratora
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()
który zakończył wszystkie połączenia i pokazał mi krytyczny komunikat „błąd”:
FATAL: terminating connection due to administrator command SQL state: 57P01
Następnie można było usunąć bazę danych
Nic mi nie działało, oprócz tego, że zalogowałem się za pomocą pgAdmin4, a na pulpicie nawigacyjnym odłączyłem wszystkie połączenia oprócz pgAdmin4, a następnie mogłem zmienić nazwę, klikając prawym przyciskiem myszy bazę danych i właściwości, i wpisałem nową nazwę.