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


161

Кожен раз, коли я намагаюся скинути базу даних, я отримую:

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';

Я припинив з'єднання з цієї БД, але якщо я спробую скинути базу даних після цього, якимось чином хтось автоматично підключається до цієї бази даних і видає цю помилку. Що може це робити? Ніхто не використовує цю базу даних, крім мене.

Відповіді:


194

Ви можете запобігти майбутнім з'єднанням:

REVOKE CONNECT ON DATABASE thedb FROM public;

(та, можливо, інших користувачів / ролей; див. \l+вpsql )

Потім ви можете припинити всі з'єднання з цим db, крім власного:

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;
Михайло Васін

155

Кожен раз, коли я намагаюся скинути базу даних, я отримую:

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

Пляма на! Дякую! 🎉
слайма

Працював ідеально. Дякую.
Мустафа Магді

34

Я знайшов рішення цієї проблеми, спробуйте запустити цю команду в терміналі

ps -ef | grep postgres

процес вбивства за допомогою цієї команди

sudo kill -9 PID

Ні, це занадто жорсткий код, що робити, якщо ви не можете вбити процес pg, оскільки у вас є інші бази даних, до яких можна отримати доступ?
Володимир Стажилов

2
@VladimirStazhilov Він покаже ім'я бази даних та pid цієї бази даних. хтось може вибрати певне вбивство Pid лише для цієї конкретної бази даних.
Дінеш Паллапа

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

Тепер вимкніть всі процеси за допомогою db:

  1. Клацніть ім'я БД
  2. Натисніть Інформаційна панель> Сеанси
  3. Клацніть на кнопку оновлення
  4. Клацніть на значку видалення (x) біля кожного процесу, щоб закінчити їх

Тепер має бути можливість видалити db.


Це добре працює - я протестував його з PgAdmin 4.5 та з PostgreSQL 11.2, складений Visual C ++ build 1914, 64-розрядний (Windows).
vab2048

2
Це найкраще рішення, я думаю. Це працює дуже добре!
Лахіру

10

Якщо жодного потенційного впливу на інші сервіси на вашій машині немає, просто service postgresql restart


8

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




це працювало і для мене з Postgress.app на Mac. У такому випадку ви зупиняєте / запускаєте сервер
Juan José Ramírez


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 / system, де це можна вважати прийнятним. Це не прийнятно для виробничого коду.


Ось повний хак в 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 із вибраних результатів)

ВИБІР pg_terminate_backend (propid);

Примітка: Убивання обраного запиту не робить ніякого поганого впливу


2

REVOKE CONNECTне перешкоджатиме з'єднанням власника db або суперпользователя. Тож якщо ви не хочете, щоб хтось підключав db, команда follow може бути корисною.

alter database pilot allow_connections = off;

Потім використовуйте:

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

1
Дякую ... ЗАМЕНИТИ ЗВ'ЯЗКУ було недостатньо для мого сценарію.
volpato

1

Хоча я вважав, що два відповіді, отримані за зверненнями, корисні в інших випадках, сьогодні найпростішим способом вирішити проблему було зрозуміти, що PyCharm може тримати сеанс відкритим, і якщо я натиснув Stopна PyCharm, це може допомогти. Коли pgAdmin4 був відкритий у браузері, я зробив це, і майже одразу побачив, як статистика сеансів бази даних знизилася до 0, після чого я зміг скинути базу даних.


"PyCharm може тримати сеанс відкритим"? Як? Я запускаю одиничні тести в терміналі PyCharm (frontend Python with peewee, backkend Postgres), тобто кнопка "Стоп" замурована, і я все-таки зберігаю ці помилки ...
Laryx Decidua

@LaryxDecidua Я вважаю, що в моєму випадку я мав мати примірник служби, що працює в PyCharm, який використовував db. Якщо ви виходите з PyCharm, чи зменшується кількість екземплярів до 0, що дозволяє вам скинути db? Якщо так, то має бути щось (провідник баз даних, SQL-запит, щось інше), що все ще підключено.
hlongmore

1

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

brew services restart postgresql

-1

У терміналі спробуйте цю команду:

ps -ef | grep postgres

ви побачите:

501 1445 3645 0 00:05 0: 00,03 postgres: sasha dbname [local] idle

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

Ви можете видалити це

sudo kill -9 3645

Після цього запустіть ваше PostgreSQL-з'єднання.

Почніть вручну:

pg_ctl -D /usr/local/var/postgres start
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.