Postgresql - không thể hủy cơ sở dữ liệu do một số kết nối tự động đến DB


160

Bất cứ khi nào tôi cố gắng bỏ cơ sở dữ liệu, tôi nhận được:

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

Khi tôi sử dụng:

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

Tôi đã chấm dứt kết nối từ DB đó, nhưng nếu tôi cố gắng bỏ cơ sở dữ liệu thì bằng cách nào đó, ai đó sẽ tự động kết nối với cơ sở dữ liệu đó và đưa ra lỗi này. Điều gì có thể làm điều đó? Không ai sử dụng cơ sở dữ liệu này, ngoại trừ tôi.

Câu trả lời:


192

Bạn có thể ngăn chặn các kết nối trong tương lai:

REVOKE CONNECT ON DATABASE thedb FROM public;

(và có thể cả người dùng / vai trò khác; xem \l+trong psql)

Sau đó, bạn có thể chấm dứt tất cả các kết nối tới db này ngoại trừ chính bạn:

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

Trên các phiên bản cũ hơn pidđã được gọi procpidđể bạn sẽ phải đối phó với điều đó.

Vì bạn đã thu hồi CONNECTquyền, bất cứ điều gì đang cố gắng tự động kết nối sẽ không còn có thể làm như vậy.

Bây giờ bạn sẽ có thể bỏ DB.

Điều này sẽ không hoạt động nếu bạn đang sử dụng kết nối siêu người dùng cho các hoạt động bình thường, nhưng nếu bạn đang làm điều đó trước tiên bạn cần khắc phục vấn đề đó.


19
Nếu bạn nhập một cơ sở dữ liệu khác có cùng tên sau này, hãy cấp khả năng kết nối cho công chúng trở lại:GRANT CONNECT ON DATABASE thedb TO public;
Mikhail Vasin

153

Bất cứ khi nào tôi cố gắng bỏ cơ sở dữ liệu, tôi nhận được:

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

Trước tiên, bạn cần thu hồi

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

Sau đó sử dụng:

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

Nó chắc chắn sẽ làm việc.


5
Điều này đã làm điều đó cho tôi. Cảm ơn
rpivovar

Tại chỗ trên! Cảm ơn bạn! 🎉
slajma

Làm việc hoàn hảo. Cảm ơn bạn.
Mustafa Magdi

34

Tôi tìm thấy một giải pháp cho vấn đề này hãy thử chạy lệnh này trong terminal

ps -ef | grep postgres

giết quá trình bằng lệnh này

sudo kill -9 PID

Không, đó là mã cứng, nếu bạn không thể xử lý pg vì bạn có các cơ sở dữ liệu khác đang được truy cập thì sao?
Vladimir Stazhilov

2
@VladimirStazhilov Nó sẽ hiển thị tên cơ sở dữ liệu và pid của cơ sở dữ liệu đó. ai đó có thể chọn pid cụ thể chỉ giết cơ sở dữ liệu cụ thể đó.
Dinesh Pallapa

29

Chỉ cần kiểm tra kết nối là gì, đến từ đâu. Bạn có thể thấy tất cả điều này trong:

select * from pg_stat_activity where datname = 'TARGET_DB';

Có lẽ đó là kết nối của bạn?


4
sudo kill -9 PID trong thiết bị đầu cuối sau khi thấy kết quả
Dan Rey Oquindo

24

Nó có nghĩa là một người dùng khác đang truy cập cơ sở dữ liệu. Đơn giản chỉ cần khởi động lại PostgreSQL. Lệnh này sẽ thực hiện các mẹo

root@kalilinux:~#sudo service postgresql restart

Sau đó thử thả cơ sở dữ liệu:

postgres=# drop database test_database;

Điều này sẽ làm các mẹo.


11

Giải pháp pgAdmin 4 bằng UI

Trước tiên hãy bật hoạt động hiển thị trên bảng điều khiển nếu bạn chưa:

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

Bây giờ hãy vô hiệu hóa tất cả các quy trình bằng cách sử dụng db:

  1. Nhấp vào tên DB
  2. Nhấp vào Bảng điều khiển> Phiên
  3. Nhấp vào làm mới biểu tượng
  4. Nhấp vào biểu tượng xóa (x) bên cạnh mỗi quy trình để kết thúc chúng

Bây giờ có thể xóa db.


Điều này hoạt động tốt - Tôi đã thử nghiệm nó với PGAdmin 4.5 và với PostgreSQL 11.2, được biên dịch bởi Visual C ++ build 1914, 64-bit (Windows).
vab2048

2
Đây là giải pháp tốt nhất tôi nghĩ. Điều này hoạt động thực sự tốt!
Lahiru

10

Nếu không có tác động tiềm năng đối với các dịch vụ khác trên máy của bạn, chỉ cần service postgresql restart


8

Giải pháp:
1. Tắt máy chủ PG 2. Nó sẽ ngắt kết nối tất cả các kết nối đang hoạt động 3. Khởi động lại máy chủ PG 4. Hãy thử lệnh của bạn
nhập mô tả hình ảnh ở đây




điều này cũng hiệu quả với tôi với PostTHER.app trên máy Mac. Trong trường hợp đó, bạn dừng / khởi động máy chủ
Juan Jose Ramírez

7

Đơn giản như vậy

sudo service postgresql restart

3

Trong trường hợp của tôi, tôi đang sử dụng AWS Redshift (dựa trên Postgres). Và có vẻ như không có kết nối nào khác với DB, nhưng tôi cũng gặp lỗi tương tự.

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

Trong trường hợp của tôi, có vẻ như cụm cơ sở dữ liệu vẫn đang thực hiện một số xử lý trên cơ sở dữ liệu và trong khi không có kết nối bên ngoài / người dùng nào khác, cơ sở dữ liệu vẫn được sử dụng nội bộ. Tôi tìm thấy điều này bằng cách chạy như sau:

SELECT * FROM stv_sessions;

Vì vậy, hack của tôi là viết một vòng lặp trong mã của tôi, tìm kiếm các hàng có tên cơ sở dữ liệu của tôi trong đó. (tất nhiên vòng lặp không phải là vô hạn và là vòng lặp buồn ngủ, v.v.)

SELECT * FROM stv_sessions where db_name = 'XYZ';

Nếu hàng được tìm thấy, tiến hành xóa từng PID, từng cái một.

SELECT pg_terminate_backend(PUT_PID_HERE);

Nếu không tìm thấy hàng, tiến hành thả cơ sở dữ liệu

DROP DATABASE XYZ;

Lưu ý: Trong trường hợp của tôi, tôi đang viết các bài kiểm tra đơn vị / hệ thống Java, trong đó điều này có thể được coi là chấp nhận được. Điều này không được chấp nhận cho mã sản xuất.


Đây là bản hack hoàn chỉnh, trong Java (bỏ qua các lớp kiểm tra / tiện ích của tôi).

  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

Theo tôi có một số truy vấn nhàn rỗi đang chạy trong backgroud.

  1. Hãy thử hiển thị các truy vấn đang chạy trước
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. giết truy vấn nhàn rỗi (Kiểm tra xem họ đang tham chiếu cơ sở dữ liệu trong câu hỏi hay bạn có thể giết tất cả chúng hoặc giết một cụ thể bằng cách sử dụng pid từ các kết quả được chọn)

CHỌN pg_terminate_backend (Procpid);

Lưu ý: Giết một truy vấn chọn không gây ra tác động xấu nào


2

REVOKE CONNECTsẽ không ngăn chặn các kết nối từ chủ sở hữu db hoặc siêu người dùng. Vì vậy, nếu bạn không muốn ai kết nối db, lệnh follow có thể hữu ích.

alter database pilot allow_connections = off;

Sau đó sử dụng:

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

1
Cảm ơn ... REVOKE CONNECT không đủ cho kịch bản của tôi.
volpato

1

Mặc dù tôi thấy hai câu trả lời nâng cao hữu ích trong các dịp khác, hôm nay, cách đơn giản nhất để giải quyết vấn đề là nhận ra rằng PyCharm có thể giữ một phiên mở và nếu tôi nhấp Stopvào PyCharm, điều đó có thể giúp ích. Khi pgAdmin4 mở trong trình duyệt, tôi đã làm như vậy và gần như ngay lập tức thấy các số liệu thống kê phiên Cơ sở dữ liệu giảm xuống 0, tại thời điểm đó tôi có thể bỏ cơ sở dữ liệu.


"PyCharm có thể giữ một phiên mở"? Làm sao? Tôi chạy thử nghiệm đơn vị trong thiết bị đầu cuối của PyCharm (frontend Python với peewee, backend Postgres), tức là nút "Dừng" bị mờ đi và tôi vẫn giữ những lỗi này ...
Laryx Decidua

@LaryxDecidua Tôi tin rằng, trong trường hợp của tôi, tôi phải có một phiên bản của một dịch vụ chạy trong PyCharm đã sử dụng db. Nếu bạn thoát PyCharm, số lượng phiên bản giảm xuống 0, cho phép bạn bỏ db? Nếu vậy, phải có một cái gì đó (cơ sở dữ liệu thám hiểm, truy vấn SQL, một cái gì đó khác) vẫn được kết nối.
hlongmore

0

Trong macOS, hãy thử khởi động lại cơ sở dữ liệu postgresql thông qua bảng điều khiển bằng lệnh:

brew services restart postgresql

-1

Trong thiết bị đầu cuối hãy thử lệnh này:

ps -ef | grep postgres

bạn sẽ thấy như:

501 1445 3645 0 12:05 AM 0: 00.03 postgres: sasha dbname [local] nhàn rỗi

Số thứ ba (3645) là PID.

Bạn có thể xóa cái này

sudo kill -9 3645

Và sau đó bắt đầu kết nối PostgreSQL của bạn.

Bắt đầu bằng tay:

pg_ctl -D /usr/local/var/postgres start
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.