บังคับให้ปล่อย db ขณะที่ผู้อื่นอาจเชื่อมต่อ


103

ฉันต้องการลบฐานข้อมูลออกจากคลัสเตอร์ PostgreSQL DB ฉันจะทำอย่างไรแม้ว่าจะมีการเชื่อมต่อที่ใช้งานอยู่? ฉันต้องการเรียงลำดับของ-forceธงที่จะลดการเชื่อมต่อทั้งหมดแล้ว DB

ฉันจะใช้มันได้อย่างไร

ฉันกำลังใช้งานdropdbอยู่ แต่เครื่องมืออื่นเป็นไปได้

คำตอบ:


154

ใน PostgreSQL *คุณไม่สามารถวางฐานข้อมูลในขณะที่ลูกค้าเชื่อมต่อกับมัน

อย่างน้อยไม่ได้มีdropdbยูทิลิตี้ - ซึ่งเป็นเพียง wrapper ง่าย ๆ รอบDROP DATABASEแบบสอบถามเซิร์ฟเวอร์

วิธีแก้ปัญหาที่แข็งแกร่งค่อนข้างดังต่อไปนี้:

เชื่อมต่อกับเซิร์ฟเวอร์ของคุณเป็นsuperuserใช้psqlหรือไคลเอนต์อื่น ๆ ไม่ได้ใช้ฐานข้อมูลที่คุณต้องการที่จะลดลง

psql -h localhost postgres postgres

ตอนนี้ใช้ไคลเอนต์ฐานข้อมูลธรรมดาคุณสามารถบังคับให้ปล่อยฐานข้อมูลโดยใช้สามขั้นตอนง่าย ๆ :

  1. ตรวจสอบให้แน่ใจว่าไม่มีใครสามารถเชื่อมต่อกับฐานข้อมูลนี้ คุณสามารถใช้หนึ่งในวิธีต่อไปนี้ (วิธีที่สองดูปลอดภัยกว่า แต่ไม่ได้ป้องกันการเชื่อมต่อจากผู้ใช้ระดับสูง)

    /* Method 1: update system catalog */
    UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'mydb';
    
    /* Method 2: use ALTER DATABASE. Superusers still can connect!
    ALTER DATABASE mydb CONNECTION LIMIT 0; */
  2. pg_terminate_backendขาดการเชื่อมต่อกองทัพของลูกค้าทั้งหมดที่เชื่อมต่อไปยังฐานข้อมูลนี้โดยใช้

    SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE datname = 'mydb';
    
    /* For old versions of PostgreSQL (up to 9.1), change pid to procpid:
    
    SELECT pg_terminate_backend(procpid)
    FROM pg_stat_activity
    WHERE datname = 'mydb'; */
  3. ปล่อยฐานข้อมูล

    DROP DATABASE mydb;

ขั้นตอนที่ 1 ต้องการสิทธิ์ superuserสำหรับวิธีที่ 1 และสิทธิ์ของเจ้าของฐานข้อมูลสำหรับวิธีที่ 2 ขั้นตอนที่ 2 ต้องใช้สิทธิ์superuser ขั้นตอนที่ 3 ต้องใช้สิทธิ์ของเจ้าของฐานข้อมูล


* สิ่งนี้ใช้กับ PostgreSQL ทุกเวอร์ชันจนถึงเวอร์ชัน 11



ดังนั้นฉันไม่รู้ว่าฉันทำอะไรผิด แต่ตอนนี้ฉันไม่สามารถเชื่อมต่อกับฐานข้อมูลที่ฉันกำหนดเป้าหมายได้! ฉันไม่สามารถปล่อยมันได้เพราะมันบอกว่า "ไม่สามารถลบฐานข้อมูลการบำรุงรักษาได้"
Matt Skeldon

@ MattSkeldon ไม่ทราบว่าข้อความนี้หมายถึงอะไร ใน Vanilla PostgreSQL คุณสามารถวางฐานข้อมูลใด ๆ ยกเว้น template0 & template1 บางทีคุณอาจใช้รุ่นที่ไม่ใช่ฟรี / ใช้ในเชิงพาณิชย์? อาจเป็นปัญหาของลูกค้าไม่ใช่ปัญหาเซิร์ฟเวอร์? คุณลอง psql ไหม
filiprem

น่าเสียดายที่ฉันมาจากพื้นหลังของ SQL การใช้ PGSQL กำลังถูกใช้เนื่องจากสถานะที่ไม่ใช่เชิงพาณิชย์ / ฟรี
Matt Skeldon

สิ่งนี้ไม่ได้ผลสำหรับฉันที่มีเซสชันซอมบี้ที่ใช้เวลานาน pg_terminate_backend () ไม่ฆ่าเซสชันเหล่านั้นดังนั้นฉันยังติดอยู่เล็กน้อยเกี่ยวกับสิ่งที่ต้องทำ: ฉันเป็น Postgres su แต่ฉันไม่สามารถเข้าถึงเซิร์ฟเวอร์ที่ใช้งานอยู่
Alexander

6

มีเป็นวิธีการที่จะทำเช่นนี้กับสาธารณูปโภคเปลือกdropdbและpg_ctl(หรือpg_ctlclusterใน Debian และสารอนุพันธ์) แต่วิธีการของ @ filipremนั้นเหนือกว่าด้วยเหตุผลหลายประการ:

  • มันตัดการเชื่อมต่อผู้ใช้จากฐานข้อมูลที่เป็นปัญหาเท่านั้น
  • ไม่จำเป็นต้องรีสตาร์ททั้งคลัสเตอร์
  • มันป้องกันการเชื่อมต่อใหม่ทันทีอาจทำให้dropdbคำสั่งเสีย

ฉันพูดman pg_ctlcluster:

ด้วย--forceตัวเลือกโหมด "เร็ว" จะใช้ซึ่งย้อนกลับธุรกรรมที่ใช้งานอยู่ทั้งหมดให้ยกเลิกการเชื่อมต่อไคลเอ็นต์ทันทีและปิดเครื่องอย่างหมดจด หากไม่ได้ผลระบบจะพยายามปิดระบบอีกครั้งในโหมด "ทันที" ซึ่งอาจทำให้คลัสเตอร์อยู่ในสถานะไม่สอดคล้องกันและจะทำให้การกู้คืนทำงานในการเริ่มต้นครั้งถัดไป หากสิ่งนี้ยังไม่ช่วยกระบวนการ postmaster จะถูกฆ่า ออกด้วย 0 เมื่อสำเร็จโดยมี 2 ถ้าเซิร์ฟเวอร์ไม่ได้ทำงานและมี 1 เมื่อเงื่อนไขความล้มเหลวอื่น ๆ โหมดนี้ควรใช้เฉพาะเมื่อเครื่องกำลังจะปิด

pg_ctlcluster 9.1 main restart --force

หรือ

pg_ctl restart -D datadir -m fast

หรือ

pg_ctl restart -D datadir -m immediate

ตามด้วยทันที:

dropdb mydb

อาจเป็นสคริปต์สำหรับการทดแทนอย่างฉับพลัน


4
ไม่เพียง แต่มันจะน้อยกว่าอุดมคติในขณะที่มันเตะอินสแตนซ์ postgres แบบเต็ม แต่ไม่รับประกันว่าจะทำงานได้ เป็นไปได้ที่ไคลเอ็นต์จะเชื่อมต่อระหว่างเวลาที่คุณรีสตาร์ทเซิร์ฟเวอร์และพยายามเรียกใช้ dropdb อีกครั้ง @filiprem คำตอบข้างต้นปิดการใช้งานการเชื่อมต่อทั้งหมดไปยังฐานข้อมูลก่อนที่จะตัดการเชื่อมต่อและจะทำให้ฐานข้อมูลอื่น ๆ ขึ้น
Jim Mitchener

6

ใช้คำตอบของ @ filiprem ในกรณีของฉันและทำให้มันง่ายขึ้น:

-- Connecting to the current user localhost's postgres instance
psql

-- Making sure the database exists
SELECT * from pg_database where datname = 'my_database_name'

-- Disallow new connections
UPDATE pg_database SET datallowconn = 'false' WHERE datname = 'my_database_name';
ALTER DATABASE my_database_name CONNECTION LIMIT 1;

-- Terminate existing connections
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'my_database_name';

-- Drop database
DROP DATABASE my_database_name

0

หากคุณอยู่ในประเภท RDS ที่การเชื่อมต่อที่ไม่มีฐานข้อมูลถูกเลือกจะนำคุณไปสู่ฐานข้อมูลที่คุณขอให้สร้างขึ้นโดยค่าเริ่มต้นคุณสามารถทำสิ่งนี้ได้เพื่อให้คุณได้รับการเชื่อมต่อล่าสุดที่เปิดอยู่

 DROP DATABASE IF EXISTS temporary_db_that_shouldnt_exist; 

 CREATE DATABASE temporary_db_that_shouldnt_exist with OWNER your_user; 

 \connect temporary_db_that_shouldnt_exist 
 SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'the_db_you_want_removed'; 


 DROP DATABASE IF EXISTS the_db_you_want_removed; 
 -- 
 -- Name: the_db_you_want_removed; Type: DATABASE; Schema: -; Owner: your_user 
 -- 

 CREATE DATABASE savings_champion WITH TEMPLATE = template0 ENCODING = 'UTF8' LC_COLLATE = 'en_US.UTF-8' LC_CTYPE = 'en_US.UTF-8'; 


 ALTER DATABASE the_db_you_want_removed OWNER TO your_user; 

 \connect the_db_you_want_removed 

 DROP DATABASE IF EXISTS temporary_db_that_shouldnt_exist;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.