Làm thế nào để loại bỏ cơ sở dữ liệu PostgreSQL nếu có kết nối hoạt động với nó?


648

Tôi cần phải viết một tập lệnh sẽ loại bỏ cơ sở dữ liệu PostgreSQL. Có thể có rất nhiều kết nối với nó, nhưng kịch bản nên bỏ qua điều đó.

DROP DATABASE db_nameTruy vấn tiêu chuẩn không hoạt động khi có kết nối mở.

Làm thế nào tôi có thể giải quyết vấn đề?


1
Bạn đang dùng phiên bản nào của PostgreSQL?
Kuberchaun

1
Vấn đề: Trong khi bạn có thể giết các phiên được kết nối với cơ sở dữ liệu, chúng có thể kết nối lại nhanh đến mức bạn vẫn không thể bỏ cơ sở dữ liệu. Hạnh phúc bài đăng này cho thấy cách khóa các kết nối mới, do đó bạn có thể hủy các kết nối hiện tại và hủy
Max Murphy

1
Tôi thấy câu trả lời này trên dba.stackexchange rất hữu ích dba.stackexchange.com/a/11895/163539 - ngắn gọn nhưng đủ giải thích.
hlongmore

Câu trả lời:


1093

Điều này sẽ loại bỏ các kết nối hiện có ngoại trừ của bạn:

Truy vấn pg_stat_activityvà nhận các giá trị pid bạn muốn giết, sau đó cấp SELECT pg_terminate_backend(pid int)cho chúng.

PostgreSQL 9.2 trở lên:

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
  AND pid <> pg_backend_pid();

PostgreSQL 9.1 trở xuống:

SELECT pg_terminate_backend(pg_stat_activity.procpid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = 'TARGET_DB' -- ← change this to your DB
  AND procpid <> pg_backend_pid();

Khi bạn ngắt kết nối tất cả mọi người, bạn sẽ phải ngắt kết nối và đưa ra lệnh DROP DATABASE từ một kết nối từ cơ sở dữ liệu khác, không phải là cơ sở dữ liệu mà bạn đang cố gắng bỏ.

Lưu ý đổi tên của procpidcột thành pid. Xem chủ đề danh sách gửi thư này .


11
Và tất nhiên, hãy chắc chắn thực hiện điều đó từ kết nối db không phải là kết nối với 'TARGET_DB', nếu không, bạn sẽ nhận được 'LRI'. Kết nối 'postgres' hoạt động tốt.
Cướp

3
Trên thực tế, nó sẽ ngắt kết nối từng khách hàng một và nếu khách hàng của bạn ở giữa danh sách thì nó cũng sẽ bị ngắt kết nối. Kết quả là một số kết nối sẽ tồn tại. Vì vậy, câu trả lời đúng là của Craig Ringer (xem bên dưới). CHỌN pg_terminate_backend (pg_stat_activity.pid) TỪ pg_stat_activity WHERE datname = current_database () VÀ pg_stat_activity.pid <> pg_backend_pid ();
Andrew Selivanov

1
Làm cách nào tôi có thể ngắt kết nối các kết nối sau khi chúng kết thúc với giao dịch hiện tại của chúng và sau đó thả (các) bảng trong câu hỏi?
paulkon

5
Trong trường hợp của tôi, các máy khách sẽ kết nối lại nhanh chóng, vì vậy việc đặt nó ngay trước khi ; drop database TARGET_DB;hoạt động tốt trong trường hợp của tôi để đảm bảo db đã biến mất vào thời điểm mọi thứ bắt đầu thử lại.
Mat Schaffer

1
Tôi thậm chí sẽ trả tiền cho a dropdb --force.
Torsten Bronger

125

Trong PostgreSQL 9.2 trở lên, để ngắt kết nối mọi thứ trừ phiên của bạn khỏi cơ sở dữ liệu bạn được kết nối với:

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

Trong các phiên bản cũ hơn, nó chỉ thay đổi pidthành procpid. Để ngắt kết nối với cơ sở dữ liệu khác, chỉ cần thay đổicurrent_database() tên của cơ sở dữ liệu bạn muốn ngắt kết nối người dùng.

Bạn có thể muốn REVOKEcác CONNECTngay từ những người sử dụng cơ sở dữ liệu trước khi ngắt kết nối người sử dụng, nếu không người dùng chỉ sẽ tiếp tục kết nối lại và bạn sẽ không bao giờ có cơ hội để thả DB. Xem bình luận này và câu hỏi liên quan đến nó, Làm cách nào để tách tất cả người dùng khác khỏi cơ sở dữ liệu .

Nếu bạn chỉ muốn ngắt kết nối người dùng nhàn rỗi, hãy xem câu hỏi này .


3
CHỌN pg_terminate_backend (pg_stat_activity.pid) TỪ pg_stat_activity WHERE datname = current_database () VÀ pg_stat_activity.pid <> pg_backend_pid ();
Andrew Selivanov

26

Bạn có thể tắt tất cả các kết nối trước khi hủy cơ sở dữ liệu bằng cách sử dụng pg_terminate_backend(int)chức năng.

Bạn có thể nhận được tất cả các phụ trợ đang chạy bằng cách sử dụng chế độ xem hệ thống pg_stat_activity

Tôi không hoàn toàn chắc chắn, nhưng những điều sau đây có thể sẽ giết tất cả các phiên:

select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'doomed_database'

Tất nhiên bạn có thể không được kết nối với cơ sở dữ liệu đó


19

Tùy thuộc vào phiên bản postgresql của bạn, bạn có thể gặp phải một lỗi, điều đó làm cho pg_stat_activity việc bỏ qua các kết nối hoạt động từ những người dùng bị đánh rơi. Các kết nối này cũng không được hiển thị bên trong pgAdminIII.

Nếu bạn đang thực hiện kiểm tra tự động (trong đó bạn cũng tạo người dùng) thì đây có thể là một tình huống có thể xảy ra.

Trong trường hợp này, bạn cần hoàn nguyên các truy vấn như:

 SELECT pg_terminate_backend(procpid) 
 FROM pg_stat_get_activity(NULL::integer) 
 WHERE datid=(SELECT oid from pg_database where datname = 'your_database');

LƯU Ý: Trong 9.2+ bạn sẽ thay đổi procpidthành pid.


1
Đó là những gì tôi đang tìm kiếm nhưng vì (giả sử là 9.2 trở lên), bạn phải xóa tham chiếu đến pg_stat_activity và thay đổi Procpid thành pid.
MDR

2
Sau khi thay đổi procpidthành pidđoạn trích này hoạt động vào ngày 9.3.
jb.

thậm chí không loại bỏ pg_stat_activity? Tôi đã nhận được một lỗi vào ngày 9.2
MDR

ĐỒNG Ý. Bây giờ tôi hiểu, đó là một lỗi đánh máy. Cảm ơn!
jb.

2
Từ 9.3 trở lên CHỌN pg_terminate_backend (pid) TỪ pg_stat_get_activity (NULL :: số nguyên) WHERE datid = (CHỌN oid từ pg_database trong đó datname = 'your_database');
Shawn Vader

17

Tôi nhận thấy rằng postgres 9.2 bây giờ gọi pid cột chứ không phải là Procpid.

Tôi có xu hướng gọi nó từ vỏ:

#!/usr/bin/env bash
# kill all connections to the postgres server
if [ -n "$1" ] ; then
  where="where pg_stat_activity.datname = '$1'"
  echo "killing all connections to database '$1'"
else
  echo "killing all connections to database"
fi

cat <<-EOF | psql -U postgres -d postgres 
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
${where}
EOF

Hy vọng rằng nó hữu ích. Cảm ơn @JustBob cho sql.


15

Tôi chỉ khởi động lại dịch vụ trong Ubuntu để ngắt kết nối các máy khách được kết nối.

sudo service postgresql stop
sudo service postgresql start

psql
DROP DATABASE DB_NAME;

10

Trong lệnh Linux Prompt, trước tiên tôi sẽ dừng tất cả các quy trình postgresql đang chạy bằng cách gõ lệnh này sudo /etc/init.d/postgresql khởi động lại

gõ lệnh bg để kiểm tra xem các tiến trình postgresql khác có còn chạy không

sau đó theo sau là dbdb dbname để thả cơ sở dữ liệu

sudo /etc/init.d/postgresql restart
bg
dropdb dbname

Điều này làm việc cho tôi trên dấu nhắc lệnh linux


6
Điều này là không tốt nếu bạn có nhiều cơ sở dữ liệu và chỉ muốn bỏ kết nối cho một DB. Điều này sẽ giết tất cả các kết nối. Đó là một chút "búa tạ-y".
Nick

2
@Nick đúng nhưng hãy nhớ rằng chúng tôi đang khởi động lại tất cả các kết nối và dừng hoàn toàn chúng
Maurice Elagu

10

PostgreSQL 9.2 trở lên:

SELECT pg_terminate_backend(pid)FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'


Điều đó cũng không chấm dứt kết nối tích cực?
Cocowalla

8

Đây là hack của tôi ... = D

# Make sure no one can connect to this database except you!
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "UPDATE pg_database SET datallowconn=false WHERE datname='<DATABASE_NAME>';"

# Drop all existing connections except for yours!
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "SELECT pg_terminate_backend(pg_stat_activity.pid) FROM pg_stat_activity WHERE pg_stat_activity.datname = '<DATABASE_NAME>' AND pid <> pg_backend_pid();"

# Drop database! =D
sudo -u postgres /usr/pgsql-9.4/bin/psql -c "DROP DATABASE <DATABASE_NAME>;"

Tôi đặt câu trả lời này vì bao gồm một lệnh (ở trên) để chặn các kết nối mới và bởi vì bất kỳ nỗ lực nào với lệnh ...

REVOKE CONNECT ON DATABASE <DATABASE_NAME> FROM PUBLIC, <USERS_ETC>;

... không hoạt động để chặn các kết nối mới!

Cảm ơn @araqnid @GoatWalker! = D

https://stackoverflow.com/a/3185413/32373785


5

Sắp tới PostgreSQL 13 sẽ giới thiệu FORCEtùy chọn.

DỄ DÀNG

DROP DATABASE làm rơi cơ sở dữ liệu ... Ngoài ra, nếu bất kỳ ai khác được kết nối với cơ sở dữ liệu đích, lệnh này sẽ thất bại trừ khi bạn sử dụng tùy chọn FORCE được mô tả bên dưới.

LỰC LƯỢNG

Cố gắng chấm dứt tất cả các kết nối hiện có đến cơ sở dữ liệu đích. Nó không chấm dứt nếu các giao dịch được chuẩn bị, các vị trí sao chép logic tích cực hoặc đăng ký có mặt trong cơ sở dữ liệu đích.

DROP DATABASE db_name WITH (FORCE);

0

Trong trường hợp của tôi, tôi đã phải thực thi một lệnh để hủy tất cả các kết nối bao gồm cả kết nối quản trị viên đang hoạt động của tôi

SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE datname = current_database()

đã chấm dứt tất cả các kết nối và hiển thị cho tôi một thông báo 'lỗi' nghiêm trọng:

FATAL: terminating connection due to administrator command SQL state: 57P01

Sau đó có thể bỏ cơ sở dữ liệu


0

Không có gì làm việc cho tôi ngoại trừ, tôi đã đăng nhập bằng pgAdmin4 và trên Bảng điều khiển, tôi đã ngắt kết nối tất cả các kết nối ngoại trừ pgAdmin4 và sau đó có thể đổi tên bằng cách nhấp chuột phải vào cơ sở dữ liệu và thuộc tính và gõ tên mới.

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.