Postgresql - nie można usunąć bazy danych z powodu niektórych automatycznych połączeń z DB

161

Ilekroć próbuję upuścić bazę danych, otrzymuję:

ERROR:  database "pilot" is being accessed by other users
DETAIL:  There is 1 other session using the database.

Kiedy używam:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB';

Zakończyłem połączenie z tej bazy danych, ale jeśli spróbuję później zrzucić bazę danych, ktoś automatycznie łączy się z tą bazą i podaje ten błąd. Co może to robić? Nikt oprócz mnie nie korzysta z tej bazy danych.

Andrius
źródło

Odpowiedzi:

194

Możesz zapobiec przyszłym połączeniom:

REVOKE CONNECT ON DATABASE thedb FROM public;

(i prawdopodobnie inni użytkownicy / role; zobacz \l+w psql)

Następnie możesz zakończyć wszystkie połączenia z tą bazą danych oprócz własnej:

SELECT pid, pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE datname = current_database() AND pid <> pg_backend_pid();

Na starszych wersjach pidbył procpidtak nazywany, więc będziesz musiał sobie z tym poradzić.

Ponieważ cofnąłeś CONNECTprawa, wszystko, co próbowało połączyć się automatycznie, nie powinno już tego robić.

Teraz będziesz mógł upuścić DB.

To nie zadziała, jeśli używasz połączeń superużytkownika do normalnych operacji, ale jeśli to robisz, musisz najpierw rozwiązać ten problem.


Po upuszczeniu bazy danych, jeśli ponownie utworzysz bazę danych, możesz wykonać poniższe polecenie, aby przywrócić dostęp

GRANT CONNECT ON DATABASE thedb TO public;
Craig Ringer
źródło
19
Jeśli importujesz innej bazy danych o tej samej nazwie później przyznać connect zdolność do tyłu publicznym:GRANT CONNECT ON DATABASE thedb TO public;
Michaił Vasin
155

Ilekroć próbuję upuścić bazę danych, otrzymuję:

ERROR:  database "pilot" is being accessed by other users
DETAIL:  There is 1 other session using the database.

Najpierw musisz odwołać

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

Następnie użyj:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB';

To na pewno zadziała.

Suneel Kumar
źródło
5
Zrobiło to dla mnie. Dzięki
rpivovar
Na miejscu! Dziękuję Ci! 🎉
slajma
Działało idealnie. Dziękuję Ci.
Mustafa Magdi
34

Znalazłem rozwiązanie tego problemu, spróbuj uruchomić to polecenie w terminalu

ps -ef | grep postgres

zabij proces za pomocą tego polecenia

sudo kill -9 PID
Dinesh Pallapa
źródło
Nie, to zbyt twardy kod, co jeśli nie możesz pominąć procesu pg, ponieważ masz dostęp do innych baz danych?
Vladimir Stazhilov
2
@VladimirStazhilov Wyświetli nazwę bazy danych i pid tej bazy danych. ktoś może wybrać konkretny pid kill tylko w tej konkretnej bazie danych.
Dinesh Pallapa
29

Po prostu sprawdź, jakie jest połączenie, skąd pochodzi. Możesz to wszystko zobaczyć w:

select * from pg_stat_activity where datname = 'TARGET_DB';

Może to twój związek?


źródło
4
sudo kill -9 PID w terminalu po obejrzeniu wyniku
Dan Rey Oquindo
25

Oznacza to, że inny użytkownik uzyskuje dostęp do bazy danych. Po prostu zrestartuj PostgreSQL. To polecenie załatwi sprawę

root@kalilinux:~#sudo service postgresql restart

Następnie spróbuj upuścić bazę danych:

postgres=# drop database test_database;

To wystarczy.

Suman Astani
źródło
11

Rozwiązanie pgAdmin 4 przy użyciu interfejsu użytkownika

Najpierw włącz pokazuj aktywność na pulpicie nawigacyjnym, jeśli tego nie zrobiłeś:

File > Preferences > Dashboards > Display > Show Activity > true

Teraz wyłącz wszystkie procesy za pomocą db:

  1. Kliknij nazwę bazy danych
  2. Kliknij Pulpit nawigacyjny> Sesje
  3. Kliknij ikonę odświeżania
  4. Kliknij ikonę usuwania (x) obok każdego procesu, aby go zakończyć

Powinien być teraz w stanie usunąć plik db.

Andrzej
źródło
To działa dobrze - przetestowałem to z PgAdmin 4.5 i PostgreSQL 11.2, skompilowanym przez Visual C ++ build 1914, 64-bit (Windows).
vab2048
2
Myślę, że to najlepsze rozwiązanie. To działa naprawdę dobrze!
Lahiru
10

Jeśli nie ma potencjalnego wpływu na inne usługi na twoim komputerze, po prostu service postgresql restart

ScotchAndSoda
źródło
8

Rozwiązanie:
1. Zamknij serwer PG 2. Rozłączy wszystkie aktywne połączenia 3. Zrestartuj serwer PG 4. Wypróbuj swoje polecenie
wprowadź opis obrazu tutaj



amoljdv06
źródło
działało to również dla mnie z Postgress.app na Macu. W takim przypadku zatrzymujesz / uruchamiasz serwer
Juan José Ramírez
7

Proste

sudo service postgresql restart
OdkoPP
źródło
3

W moim przypadku używam AWS Redshift (na podstawie Postgres). Wygląda na to, że nie ma innych połączeń z bazą danych, ale otrzymuję ten sam błąd.

ERROR:  database "XYZ" is being accessed by other users

W moim przypadku wydaje się, że klaster bazy danych nadal przetwarza bazę danych i chociaż nie ma innych połączeń zewnętrznych / użytkowników, baza danych jest nadal używana wewnętrznie. Znalazłem to, uruchamiając następujące polecenie:

SELECT * FROM stv_sessions;

Więc mój hack polegał na napisaniu pętli w moim kodzie, szukając wierszy z nazwą mojej bazy danych. (oczywiście pętla nie jest nieskończona i jest senną pętlą itp.)

SELECT * FROM stv_sessions where db_name = 'XYZ';

W przypadku znalezienia wierszy przejdź do usuwania każdego PID, jeden po drugim.

SELECT pg_terminate_backend(PUT_PID_HERE);

Jeśli nie znaleziono żadnych wierszy, kontynuuj usuwanie bazy danych

DROP DATABASE XYZ;

Uwaga: W moim przypadku piszę testy jednostkowe / systemowe Javy, gdzie można to uznać za akceptowalne. Jest to niedopuszczalne w przypadku kodu produkcyjnego.


Oto kompletny hack w Javie (zignoruj ​​moje klasy testowe / narzędziowe).

  int i = 0;
  while (i < 10) {
    try {
      i++;
      logStandardOut("First try to delete session PIDs, before dropping the DB");
      String getSessionPIDs = String.format("SELECT stv_sessions.process, stv_sessions.* FROM stv_sessions where db_name = '%s'", dbNameToReset);
      ResultSet resultSet = databaseConnection.execQuery(getSessionPIDs);
      while (resultSet.next()) {
        int sessionPID = resultSet.getInt(1);
        logStandardOut("killPID: %s", sessionPID);
        String killSessionPID = String.format("select pg_terminate_backend(%s)", sessionPID);
        try {
          databaseConnection.execQuery(killSessionPID);
        } catch (DatabaseException dbEx) {
          //This is most commonly when a session PID is transient, where it ended between my query and kill lines
          logStandardOut("Ignore it, you did your best: %s, %s", dbEx.getMessage(), dbEx.getCause());
        }
      }

      //Drop the DB now
      String dropDbSQL = String.format("DROP DATABASE %s", dbNameToReset);
      logStandardOut(dropDbSQL);
      databaseConnection.execStatement(dropDbSQL);
      break;
    } catch (MissingDatabaseException ex) {
      //ignore, if the DB was not there (to be dropped)
      logStandardOut(ex.getMessage());
      break;
    } catch (Exception ex) {
      logStandardOut("Something went wrong, sleeping for a bit: %s, %s", ex.getMessage(), ex.getCause());
      sleepMilliSec(1000);
    }
  }
Sagan
źródło
2

Moim zdaniem w tle działa kilka bezczynnych zapytań.

  1. Spróbuj najpierw wyświetlić uruchomione zapytania
SELECT pid, age(clock_timestamp(), query_start), usename, query 
FROM pg_stat_activity 
WHERE query != '<IDLE>' AND query NOT ILIKE '%pg_stat_activity%' 
ORDER BY query_start desc;
  1. kill idle query (Sprawdź, czy odwołują się do danej bazy danych, czy możesz zabić ich wszystkich lub zabić określonego za pomocą pid z wybranych wyników)

SELECT pg_terminate_backend (procpid);

Uwaga: zabicie zapytania wybierającego nie ma żadnego złego wpływu

Joweria
źródło
2

REVOKE CONNECTnie uniemożliwi połączeń od właściciela bazy danych lub superużytkownika. Jeśli więc nie chcesz, aby ktokolwiek podłączał bazę danych, przydatne może być wykonanie polecenia.

alter database pilot allow_connections = off;

Następnie użyj:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'pilot';
piekło
źródło
1
Dzięki ... REVOKE CONNECT nie wystarczyło w moim scenariuszu.
volpato
1

Chociaż przy innych okazjach okazały się przydatne dwie odpowiedzi, które zostały do ​​góry oddane, dziś najprostszym sposobem rozwiązania problemu było uświadomienie sobie, że PyCharm może utrzymywać sesję otwartą, a jeśli Stopkliknę w PyCharm, może to pomóc. Po otwarciu pgAdmin4 w przeglądarce zrobiłem to i prawie natychmiast zauważyłem, że statystyki sesji bazy danych spadły do ​​0, w którym to momencie mogłem porzucić bazę danych.

hlongmore
źródło
„PyCharm może utrzymywać sesję otwartą”? W jaki sposób? Uruchamiam testy jednostkowe w terminalu PyCharm (frontend Python z peewee, backend Postgres), czyli przycisk "Stop" jest wyszarzony i mimo to zachowuję te błędy ...
Laryx Decidua
@LaryxDecidua Uważam, że w moim przypadku musiałem mieć wystąpienie usługi działającej w PyCharm, która korzystała z bazy danych. Jeśli wyjdziesz z PyCharm, czy liczba instancji spadnie do 0, co pozwoli ci upuścić bazę danych? Jeśli tak, to musi być coś (eksplorator bazy danych, zapytanie SQL, coś innego), co jest nadal połączone.
hlongmore
1

W macOS spróbuj zrestartować bazę danych postgresql przez konsolę za pomocą polecenia:

brew services restart postgresql
Felipe Corredor
źródło
-1

W terminalu wypróbuj to polecenie:

ps -ef | grep postgres

zobaczysz jak:

501 1445 3645 0 12:05 AM 0: 00.03 postgres: sasha dbname [lokalnie] idle

Trzecia liczba (3645) to PID.

Możesz to usunąć

sudo kill -9 3645

Następnie uruchom połączenie z PostgreSQL.

Uruchom ręcznie:

pg_ctl -D /usr/local/var/postgres start
Alexandr
źródło