Postgresql - невозможно удалить базу данных из-за некоторых автоматических подключений к БД

162

Всякий раз, когда я пытаюсь удалить базу данных, я получаю:

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

Когда я использую:

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

Я разорвал соединение с этой БД, но если я попытаюсь отбросить базу данных после этого, каким-то образом кто-то автоматически подключится к этой базе данных и выдаст эту ошибку. Что может делать это? Никто не использует эту базу данных, кроме меня.

Андрюс
источник

Ответы:

197

Вы можете предотвратить будущие подключения:

REVOKE CONNECT ON DATABASE thedb FROM public;

(и, возможно, другие пользователи / роли; см. \l+в psql)

Затем вы можете разорвать все соединения с этой базой данных, кроме ваших собственных:

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

На старых версиях pidназывался procpidтак что с этим придется иметь дело.

Поскольку вы отозвали CONNECTправа, все, что пыталось выполнить автоматическое подключение, больше не сможет этого делать.

Теперь вы сможете сбросить БД.

Это не будет работать, если вы используете суперпользовательские соединения для нормальной работы, но если вы делаете это, вам нужно сначала решить эту проблему.


После завершения удаления базы данных, если вы снова создадите базу данных, вы можете выполнить следующую команду, чтобы восстановить доступ

GRANT CONNECT ON DATABASE thedb TO public;
Крейг Рингер
источник
19
Если вы позже импортируете другую базу данных с тем же именем, предоставьте возможность подключения к общедоступной спине:GRANT CONNECT ON DATABASE thedb TO public;
Михаил Васин
156

Всякий раз, когда я пытаюсь удалить базу данных, я получаю:

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

Сначала нужно отозвать

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

Тогда используйте:

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

Это обязательно сработает.

Сунил Кумар
источник
5
Это сделало это для меня. Спасибо
rpivovar
1
Пятно на! Спасибо! 🎉
Слайма
1
Работал отлично. Спасибо.
Мустафа Магди
34

Я нашел решение этой проблемы, попробуйте запустить эту команду в терминале

ps -ef | grep postgres

убить процесс этой командой

sudo kill -9 PID
Динеш Паллапа
источник
Нет, это слишком жесткий код, что если вы не можете kiil pg process, потому что у вас есть другие базы данных, к которым обращаются?
Владимир СТАЖИЛОВ,
2
@VladimirStazhilov Это покажет имя базы данных и pid этой базы данных. кто-то может выбрать конкретный pid kill только для этой конкретной базы данных.
Динеш Паллапа
29

Просто проверьте, какова связь, откуда она идет. Вы можете увидеть все это в:

select * from pg_stat_activity where datname = 'TARGET_DB';

Возможно, это ваша связь?


источник
4
sudo kill -9 PID в терминале после просмотра результата
Dan Rey Oquindo
25

Это означает, что другой пользователь обращается к базе данных. Просто перезапустите PostgreSQL. Эта команда сделает свое дело

root@kalilinux:~#sudo service postgresql restart

Затем попробуйте сбросить базу данных:

postgres=# drop database test_database;

Это сделает свое дело.

Суман Астани
источник
11

Решение pgAdmin 4 с использованием пользовательского интерфейса

Сначала включите показывать активность на панели инструментов, если у вас нет:

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

Теперь отключите все процессы, используя базу данных:

  1. Нажмите на имя БД
  2. Нажмите Панель инструментов> Сессии
  3. Нажмите значок обновления
  4. Нажмите значок удаления (x) рядом с каждым процессом, чтобы завершить их

Теперь должны быть в состоянии удалить БД.

Андрей
источник
Это хорошо работает - я протестировал его с PgAdmin 4.5 и PostgreSQL 11.2, скомпилированными в Visual C ++ build 1914, 64-bit (Windows).
vab2048
2
Это лучшее решение, я думаю. Это работает очень хорошо!
Лахиру
10

Если нет потенциального влияния на другие службы на вашем компьютере, просто service postgresql restart

ScotchAndSoda
источник
8

Решение:
1. Выключите Pg-сервер. 2. Он отключит все активные соединения. 3. Перезапустите Pg-сервер. 4. Попробуйте ввести команду.
введите описание изображения здесь



amoljdv06
источник
это работало и для меня с Postgress.app на Mac. В этом случае вы останавливаете / запускаете сервер
Хуан Хосе Рамирес
7

Просто как тот

sudo service postgresql restart
OdkoPP
источник
3

В моем случае я использую AWS Redshift (на основе Postgres). И кажется, что нет никаких других подключений к БД, но я получаю эту же ошибку.

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

В моем случае кажется, что кластер базы данных все еще выполняет некоторую обработку в базе данных, и, хотя нет никаких других внешних / пользовательских подключений, база данных все еще используется внутри. Я нашел это, запустив следующее:

SELECT * FROM stv_sessions;

Так что я взломал написать цикл в моем коде, ища строки с именем моей базы данных. (конечно цикл не бесконечный, а сонный цикл и т. д.)

SELECT * FROM stv_sessions where db_name = 'XYZ';

Если строки найдены, продолжайте удалять каждый PID, один за другим.

SELECT pg_terminate_backend(PUT_PID_HERE);

Если строк не найдено, перейдите к удалению базы данных

DROP DATABASE XYZ;

Примечание: в моем случае я пишу модульные / системные тесты Java, где это можно считать приемлемым. Это не приемлемо для производственного кода.


Вот полный взлом в Java (игнорируйте мои тестовые / служебные классы).

  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);
    }
  }
Саган
источник
2

На мой взгляд, в фоновом режиме работают несколько пустых запросов.

  1. Попробуйте сначала показать запущенные запросы
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. запрос на уничтожение бездействия (проверьте, ссылаются ли они на рассматриваемую базу данных, или вы можете уничтожить их все или уничтожить определенный, используя pid из результатов выбора)

SELECT pg_terminate_backend (procpid);

Примечание. Убийство запроса на выборку не оказывает негативного влияния

Joweria
источник
2

REVOKE CONNECTне помешает соединениям владельца БД или суперпользователя. Поэтому, если вы не хотите, чтобы кто-либо подключал базу данных, может быть полезна команда follow.

alter database pilot allow_connections = off;

Тогда используйте:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'pilot';
ад
источник
1
Спасибо ... REVOKE CONNECT недостаточно для моего сценария.
Вольпато
1

Несмотря на то, что я нашел два ответа с верхним голосованием полезными в других случаях, сегодня самым простым способом решения проблемы было осознать, что PyCharm может держать сеанс открытым, и если я нажму Stopна PyCharm, это может помочь. Открыв в браузере pgAdmin4, я сделал это и почти сразу увидел, что статистика сеансов базы данных упала до 0, и в этот момент я смог удалить базу данных.

hlongmore
источник
"PyCharm может держать сеанс открытым"? Как? Я запускаю модульные тесты в терминале PyCharm (внешний Python с peewee, backend Postgres), то есть кнопка «Стоп» неактивна, и я все равно сохраняю эти ошибки ...
Laryx Decidua
@LaryxDecidua Я считаю, что в моем случае у меня должен был быть экземпляр службы, работающей в PyCharm, которая использовала базу данных. Если вы выйдете из PyCharm, количество экземпляров упадет до 0, что позволит вам удалить БД? Если это так, должно быть что-то (проводник базы данных, SQL-запрос, что-то еще), которое все еще подключено.
Хлонгмор
1

В macOS попробуйте перезапустить базу данных postgresql через консоль с помощью команды:

brew services restart postgresql
Фелипе Корредор
источник
-1

В терминале попробуйте эту команду:

ps -ef | grep postgres

вы увидите как:

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

Третье число (3645) - PID.

Вы можете удалить это

sudo kill -9 3645

И после этого запустите соединение с PostgreSQL.

Начать вручную:

pg_ctl -D /usr/local/var/postgres start
Александр
источник