在其他人可能已连接的情况下强制下降db


103

我需要从PostgreSQL数据库集群中删除数据库。即使有活动的连接,我该怎么办?我需要某种-force标记,它将删除所有连接,然后删除数据库。

我该如何实施?

dropdb目前正在使用,但其他工具也是可能的。

Answers:


154

在PostgreSQL *中,无法在客户端连接到数据库时删除数据库。

至少没有使用该dropdb实用程序-该实用程序只是DROP DATABASE服务器查询的简单包装。

相当强大的解决方法如下:

使用或其他客户端,以超级用户身份连接到服务器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步要求第一种方法具有超级用户特权,而第二种方法则需要数据库所有者特权。步骤2需要超级用户权限。步骤3需要数据库所有者特权。


* 这适用于所有版本的PostgreSQL,最高版本11。



所以我不知道我做错了什么,但是现在我什至无法连接到我定位的数据库!我也不能删除它,因为它说“不能删除维护数据库”
Matt Skeldon

@MattSkeldon,不知道此消息是什么意思。在Vanilla PostgreSQL中,您可以删除除template0和template1以外的任何数据库。也许您使用一些非免费/商业版本?也许是客户端问题而不是服务器问题?您尝试过psql吗?
filiprem

不幸的是,我来自SQL背景,由于非商业/免费状态,因此正在使用PGSQL。
马特·斯凯尔顿

在有长时间运行的僵尸会话的地方,这对我不起作用。pg_terminate_backend()不会终止这些会话,因此我仍然对执行该操作有些犹豫:我是Postgres su,但是我无法访问正在运行的服务器。
亚历山大

6

一种方式与外壳工具来做到这一点dropdbpg_ctl(或pg_ctlcluster在Debian和衍生物)。但是@filiprem的方法优越,原因如下:

  • 它仅使用户与相关数据库断开连接。
  • 它不需要重新启动整个群集。
  • 这样可以防止立即重新连接,从而可能破坏dropdb命令。

我引用man pg_ctlcluster

使用该--force选项时,将使用“快速”模式,该模式将回滚所有活动事务,立即断开客户端的连接,从而彻底关闭客户端。如果这不起作用,请以“立即”模式再次尝试关闭,这可能会使群集处于不一致状态,从而导致下次启动时执行恢复。如果这仍然不能解决问题,则将取消邮件管理员。成功退出时以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 2014年

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之类的方法,其中没有选择数据库的连接会将您放入默认情况下要求创建的DB中,则可以执行此变体来避免自己成为最后一个打开的连接。

 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;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.