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)

จากนั้นคุณสามารถยุติการเชื่อมต่อกับฐานข้อมูลนี้ทั้งหมดยกเว้นของคุณเอง:

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

ในรุ่นเก่าpidถูกเรียกprocpidดังนั้นคุณจะต้องจัดการกับสิ่งนั้น

เนื่องจากคุณได้เพิกถอนCONNECTสิทธิ์สิ่งที่พยายามเชื่อมต่ออัตโนมัติไม่ควรทำเช่นนั้นอีกต่อไป

ตอนนี้คุณจะสามารถลบ DB ได้แล้ว

สิ่งนี้จะไม่ทำงานหากคุณใช้การเชื่อมต่อ superuser สำหรับการทำงานปกติ แต่ถ้าคุณทำเช่นนั้นคุณต้องแก้ไขปัญหานั้นก่อน


หลังจากคุณวางฐานข้อมูลเสร็จแล้วหากคุณสร้างฐานข้อมูลอีกครั้งคุณสามารถดำเนินการด้านล่างคำสั่งเพื่อคืนค่าการเข้าถึง

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

1
จับได้เห็นชัดตรงเผง! ขอบคุณ! 🎉
slajma

1
ทำงานได้สมบูรณ์แบบ ขอบคุณ.
Mustafa Magdi

34

ฉันพบวิธีแก้ปัญหาสำหรับปัญหานี้ลองเรียกใช้คำสั่งนี้ในเทอร์มินัล

ps -ef | grep postgres

กระบวนการฆ่าโดยคำสั่งนี้

sudo kill -9 PID

ไม่มันเป็นรหัสที่ยากเกินไปถ้าคุณไม่สามารถประมวลผล kiil pg ได้เพราะคุณมีฐานข้อมูลอื่นที่กำลังเข้าถึงอยู่
Vladimir Stazhilov

2
@VladimirStazhilov มันจะแสดงชื่อฐานข้อมูลและ pid ของฐานข้อมูลนั้น บางคนสามารถเลือก pid kill เฉพาะฐานข้อมูลนั้นเท่านั้น
Dinesh Pallapa

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 solution โดยใช้ UI

ขั้นแรกให้เปิดใช้งานการแสดงกิจกรรมบนแดชบอร์ดหากคุณยังไม่ได้:

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

ตอนนี้ปิดการใช้งานกระบวนการทั้งหมดโดยใช้ db:

  1. คลิกที่ชื่อ DB
  2. คลิกแดชบอร์ด> เซสชัน
  3. คลิกที่ไอคอนรีเฟรช
  4. คลิกไอคอนลบ (x) ข้างแต่ละกระบวนการเพื่อสิ้นสุด

ตอนนี้ควรจะสามารถลบ db


สิ่งนี้ทำงานได้ดี - ฉันทดสอบด้วย PgAdmin 4.5 และ PostgreSQL 11.2 ซึ่งคอมไพล์โดย Visual C ++ build 1914, 64- บิต (Windows)
vab2048

2
นี่เป็นทางออกที่ดีที่สุดที่ฉันคิด มันใช้งานได้ดีจริงๆ!
ลาหิรุ


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 ซึ่งอาจถือว่ายอมรับได้ รหัสนี้ไม่ได้รับการยอมรับ


นี่คือแฮ็คที่สมบูรณ์ใน 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. kill แบบสอบถามที่ไม่ได้ใช้งาน (ตรวจสอบว่าพวกเขากำลังอ้างอิงฐานข้อมูลในคำถามหรือคุณสามารถฆ่าพวกเขาทั้งหมดหรือฆ่าเฉพาะโดยใช้ pid จากผลลัพธ์ที่เลือก)

เลือก pg_terminate_backend (procpid);

หมายเหตุ: การฆ่าแบบสอบถามแบบใช้เลือกข้อมูลไม่ส่งผลกระทบใด ๆ


2

REVOKE CONNECTจะไม่ป้องกันการเชื่อมต่อจากเจ้าของ db หรือ superuser ดังนั้นหากคุณไม่ต้องการให้ใครเชื่อมต่อ 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 (ส่วนหน้าของ Python กับ peewee, แบ็กเอนด์ Postgres) นั่นคือปุ่ม "Stop" เป็นสีเทาและฉันยังคงรักษาข้อผิดพลาดเหล่านี้ไว้ ...
Laryx Decidua

@ LaryxDecidua ฉันเชื่อว่าในกรณีของฉันฉันต้องมีอินสแตนซ์ของบริการที่ทำงานใน PyCharm ที่ใช้ db หากคุณออกจาก PyCharm จำนวนอินสแตนซ์จะลดลงเป็น 0 หรือไม่อนุญาตให้คุณลบฐานข้อมูล ถ้าเป็นเช่นนั้นจะต้องมีบางสิ่ง (ตัวสำรวจฐานข้อมูล, แบบสอบถาม SQL, อย่างอื่น) ที่ยังคงเชื่อมต่ออยู่
hlongmore

1

ใน macOS ลองรีสตาร์ทฐานข้อมูล postgresql ผ่านคอนโซลโดยใช้คำสั่ง:

brew services restart postgresql

-1

ใน terminal ลองคำสั่งนี้:

ps -ef | grep postgres

คุณจะเห็นเช่น:

501 1445 3645 0 12:05 AM 0: 00.03 postgres: sasha dbname [local] ว่าง

หมายเลขที่สาม (3645) คือ PID

คุณสามารถลบได้

sudo kill -9 3645

และหลังจากนั้นเริ่มการเชื่อมต่อ PostgreSQL ของคุณ

เริ่มด้วยตนเอง:

pg_ctl -D /usr/local/var/postgres start
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.