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

我该如何实现它?

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

#1 楼

已添加PostgreSQL 13:
DROP DATABASE mydb WITH (FORCE);


FORCE
尝试终止与目标数据库的所有现有连接。
如果不终止,则不会终止目标数据库中存在已准备好的事务,活动的逻辑复制槽或预订。
如果当前用户无权终止其他连接,则此操作将失败。所需的权限与第9.27.2节中所述的
pg_terminate_backend相同。如果我们无法终止连接,这也会失败。


在PostgreSQL 12和更早的版本中,当客户端连接到数据库时,您不能删除数据库。
至少,不是dropdb实用程序,它不是DROP DATABASE服务器查询的简单包装。
相当强大的解决方法如下:
使用psql或其他客户端,以超级用户身份连接到服务器。不要使用要删除的数据库。
psql -h localhost postgres postgres

现在,使用普通数据库客户端,您可以通过三个简单步骤强制删除数据库:


确保没有人可以连接到该数据库。您可以使用以下方法之一(第二种方法似乎更安全,但不会阻止超级用户的连接)。
使用以下方法强制断开连接到该数据库的所有客户端的连接: pg_terminate_backend
/* 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; */



删除数据库。
 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'; */



步骤1需要第一种方法的超级用户特权,和数据库所有者的第二个特权。步骤2需要超级用户特权。步骤3需要数据库所有者特权。

#2 楼

在我的情况下,使用@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


评论


在UPDATE行上,它应该为false而不是'false'。

– Scott P.
4月16日19:56

#3 楼

Postgres 13为FORCE添加了DROP DATABASE选项。请参阅filiprem的答案。
shell实用程序dropdb基本上只是SQL命令的包装,并且继承了相同的选项。因此,从外壳程序开始,它也变得简单可靠:
 dropdb mydb --force
 

或简称:
 dropdb mydb -f
 


对于Postgres 12及更早版本,shell实用程序dropdbpg_ctl(或Debian及其衍生版本中的pg_ctlcluster)也有一种方法。但是filiprem的方法在那里具有优越性,原因有几个:

它仅使用户与所讨论的数据库断开连接。
它不需要重新启动整个集群。
它防止立即重新连接,可能会破坏dropdb命令。

我引用man pg_ctlcluster

通过--force选项,使用了“快速”模式,该模式回滚所有活动的事务,立即断开客户端的连接,因此干净地关闭。如果这不起作用,请以“立即”模式再次尝试关闭,这会使群集处于不一致状态,从而导致下次启动时执行恢复。如果这仍然不能解决问题,则将取消邮件管理员。成功退出时以0退出,如果服务器未运行则退出,以2退出,在其他失败情况下以1退出。仅在即将关闭计算机时使用此模式。

 pg_ctlcluster 9.1 main restart --force
 


 pg_ctl restart -D datadir -m fast
 


 =“ pre-class =” lang-sh prettyprint-override“> pg_ctl restart -D datadir -m immediate
 

紧随其后的是:
 dropdb mydb
 

可能在脚本中可以立即继承。

评论


这不仅不理想,因为它会引发完整的postgres实例,而且不能保证能正常工作。在重新启动服务器的时间与尝试再次运行dropdb的时间之间,客户端可能会连接。上面@filiprem的答案会在断开连接之前禁用与数据库的所有连接,并将保持其他数据库的状态。

– Jim Mitchener
14-10-22在5:28

#4 楼

对于那些在8年后立即发现此问题的人,PostgreSQL 13最终添加了该问题要求的--force标志:
DROP DATABASE database_to_drop WITH (FORCE)

dropdb [-f/--force] database_to_drop


尝试终止与目标数据库的所有现有连接。如果目标数据库中存在准备好的事务,活动的逻辑复制槽或预订,它不会终止。
如果当前用户无权终止其他连接,则此操作将失败。所需的权限与9.27.2节中描述的pg_terminate_backend相同。如果我们无法终止连接,这也会失败。

https://www.postgresql.org/docs/13/sql-dropdatabase.html

#5 楼

如果您使用的是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;