Postgresql - tidak dapat menjatuhkan basis data karena beberapa koneksi otomatis ke DB

162

Setiap kali saya mencoba drop database saya mendapatkan:

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

Ketika saya menggunakan:

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

Saya memutuskan koneksi dari DB itu, tetapi jika saya mencoba untuk menjatuhkan database setelah itu entah bagaimana seseorang secara otomatis terhubung ke database itu dan memberikan kesalahan ini. Apa yang bisa melakukan itu? Tidak ada yang menggunakan database ini, kecuali saya.

Andrius
sumber

Jawaban:

197

Anda dapat mencegah koneksi di masa depan:

REVOKE CONNECT ON DATABASE thedb FROM public;

(dan mungkin pengguna / peran lain; lihat \l+di psql)

Anda kemudian dapat mengakhiri semua koneksi ke db ini kecuali Anda sendiri:

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

Pada versi yang lebih lama piddipanggil procpidjadi Anda harus menghadapinya.

Karena Anda telah mencabut CONNECThak, apa pun yang mencoba terhubung secara otomatis seharusnya tidak lagi dapat melakukannya.

Anda sekarang dapat menjatuhkan DB.

Ini tidak akan berfungsi jika Anda menggunakan koneksi superuser untuk operasi normal, tetapi jika Anda melakukan itu, Anda perlu memperbaiki masalah itu terlebih dahulu.


Setelah Anda selesai menjatuhkan database, jika Anda membuat database lagi, Anda dapat menjalankan perintah di bawah ini untuk mengembalikan akses

GRANT CONNECT ON DATABASE thedb TO public;
Craig Ringer
sumber
19
Jika Anda mengimpor database lain dengan nama yang sama nanti, berikan kapabilitas koneksi ke publik:GRANT CONNECT ON DATABASE thedb TO public;
Mikhail Vasin
156

Setiap kali saya mencoba drop database saya mendapatkan:

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

Pertama, Anda perlu mencabut

REVOKE CONNECT ON DATABASE TARGET_DB FROM public;

Kemudian gunakan:

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

Itu pasti akan berhasil.

Suneel Kumar
sumber
5
Ini berhasil untuk saya. Terima kasih
rpivovar
1
Temukan! Terima kasih! 🎉
slajma
1
Bekerja dengan sempurna. Terima kasih.
Mustafa Magdi
34

Saya menemukan solusi untuk masalah ini, coba jalankan perintah ini di terminal

ps -ef | grep postgres

matikan proses dengan perintah ini

sudo kill -9 PID
Dinesh Pallapa
sumber
Tidak, ini terlalu hardcode, bagaimana jika Anda tidak dapat memproses kiil pg karena Anda memiliki database lain yang sedang diakses?
Vladimir Stazhilov
2
@VladimirStazhilov Ini akan menampilkan nama basis data dan pid dari basis data itu. seseorang dapat memilih pid tertentu hanya membunuh basis data tertentu.
Dinesh Pallapa
29

Cukup periksa apa hubungannya, dari mana asalnya. Anda dapat melihat semua ini di:

select * from pg_stat_activity where datname = 'TARGET_DB';

Mungkin itu koneksi Anda?


sumber
4
sudo bunuh -9 PID di terminal setelah melihat hasilnya
Dan Rey Oquindo
25

Ini berarti pengguna lain sedang mengakses database. Cukup restart PostgreSQL. Perintah ini akan melakukan triknya

root@kalilinux:~#sudo service postgresql restart

Kemudian coba jatuhkan database:

postgres=# drop database test_database;

Ini akan melakukan triknya.

Suman Astani
sumber
11

solusi pgAdmin 4 menggunakan UI

Pertama-tama aktifkan aktivitas acara di dasbor jika Anda belum:

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

Sekarang nonaktifkan semua proses menggunakan db:

  1. Klik nama DB
  2. Klik Dasbor> Sesi
  3. Klik ikon segarkan
  4. Klik ikon hapus (x) di sebelah setiap proses untuk mengakhirinya

Seharusnya sekarang bisa menghapus db.

Andrew
sumber
Ini bekerja dengan baik - Saya mengujinya dengan PgAdmin 4.5 dan dengan PostgreSQL 11.2, dikompilasi oleh Visual C ++ build 1914, 64-bit (Windows).
vab2048
2
Ini adalah solusi terbaik yang saya pikir. Ini bekerja dengan sangat baik!
Lahiru
10

Jika tidak ada dampak potensial pada layanan lain pada mesin Anda, cukup service postgresql restart

ScotchAndSoda
sumber
8

Solusi:
1. Matikan server Pg 2. Ini akan memutuskan semua koneksi yang aktif 3. Restart Server Pg 4. Coba perintah Anda
masukkan deskripsi gambar di sini



amoljdv06
sumber
ini bekerja untuk saya juga dengan Postgress.app di Mac. Dalam hal ini Anda menghentikan / memulai server
Juan José Ramírez
7

Sederhana seperti itu

sudo service postgresql restart
OdkoPP
sumber
3

Dalam kasus saya, saya menggunakan AWS Redshift (berdasarkan Postgres). Dan tampaknya tidak ada koneksi lain ke DB, tapi saya mendapatkan kesalahan yang sama.

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

Dalam kasus saya, sepertinya cluster database masih melakukan beberapa pemrosesan pada database, dan sementara tidak ada koneksi eksternal / pengguna lain, database masih digunakan secara internal. Saya menemukan ini dengan menjalankan yang berikut:

SELECT * FROM stv_sessions;

Jadi hack saya adalah menulis satu loop dalam kode saya, mencari baris dengan nama database saya di dalamnya. (tentu saja loop tidak terbatas, dan loop mengantuk, dll)

SELECT * FROM stv_sessions where db_name = 'XYZ';

Jika baris ditemukan, lanjutkan untuk menghapus setiap PID, satu per satu.

SELECT pg_terminate_backend(PUT_PID_HERE);

Jika tidak ada baris yang ditemukan, lanjutkan untuk menjatuhkan database

DROP DATABASE XYZ;

Catatan: Dalam kasus saya, saya menulis tes unit / sistem Java, di mana ini dapat dianggap dapat diterima. Ini tidak dapat diterima untuk kode produksi.


Ini hack lengkap, di Java (abaikan kelas tes / utilitas saya).

  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
sumber
2

Menurut pendapat saya ada beberapa permintaan kosong berjalan di backgroud.

  1. Coba perlihatkan permintaan yang sedang berjalan terlebih dahulu
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 query idle (Periksa apakah mereka mereferensikan database yang bersangkutan atau Anda dapat membunuh semuanya atau membunuh spesifik menggunakan pid dari hasil yang dipilih)

SELECT pg_terminate_backend (procpid);

Catatan: Membunuh kueri pemilihan tidak berdampak buruk

Joweria
sumber
2

REVOKE CONNECTtidak akan mencegah koneksi dari pemilik db atau pengguna super. Jadi, jika Anda tidak ingin orang lain menghubungkan db, ikuti perintah mungkin berguna.

alter database pilot allow_connections = off;

Kemudian gunakan:

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'pilot';
neraka
sumber
1
Terima kasih ... REVOKE CONNECT tidak cukup pada skenario saya.
volpato
1

Sementara saya menemukan dua jawaban top-upvoted berguna pada kesempatan lain, hari ini, cara paling sederhana untuk menyelesaikan masalah adalah dengan menyadari bahwa PyCharm mungkin membuat sesi terbuka, dan jika saya mengklik Stopdi PyCharm, itu mungkin membantu. Dengan pgAdmin4 terbuka di browser, saya melakukannya, dan hampir segera melihat statistik sesi Database turun menjadi 0, pada titik mana saya bisa menjatuhkan database.

lebih lagi
sumber
"PyCharm mungkin membuat sesi terbuka"? Bagaimana? Saya menjalankan tes unit di terminal PyCharm (frontend Python dengan peewee, backend Postgres), yaitu tombol "Stop" berwarna abu-abu dan saya tetap menyimpan kesalahan ini ...
Laryx Decidua
@ LaryxDecidua Saya percaya bahwa, dalam kasus saya, saya pasti memiliki sebuah instance dari layanan yang berjalan di PyCharm yang menggunakan db. Jika Anda keluar dari PyCharm, apakah jumlah instance turun ke 0, yang memungkinkan Anda untuk menjatuhkan db? Jika demikian, pasti ada sesuatu (explorer database, query SQL, sesuatu yang lain) yang masih terhubung.
hlongmore
1

Di macOS cobalah untuk me-restart database postgresql melalui konsol menggunakan perintah:

brew services restart postgresql
Felipe Corredor
sumber
-1

Di terminal coba perintah ini:

ps -ef | grep postgres

Anda akan melihat seperti:

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

Angka ketiga (3645) adalah PID.

Anda dapat menghapus ini

sudo kill -9 3645

Dan setelah itu mulai koneksi PostgreSQL Anda.

Mulai secara manual:

pg_ctl -D /usr/local/var/postgres start
Alexandr
sumber