强制删除数据库,而其他人可能已连接

Ale*_*lex 175 postgresql maintenance

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

我该如何实施?

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

fil*_*rem 252

PostgreSQL 13添加:

DROP DATABASE mydb WITH (FORCE);
Run Code Online (Sandbox Code Playgroud)

手册:

FORCE

尝试终止与目标数据库的所有现有连接。如果目标数据库中存在准备好的事务、活动的逻辑复制槽或订阅,它不会终止。

如果当前用户没有终止其他连接的权限,这将失败。所需的权限与 相同 pg_terminate_backend,在第 9.27.2 节中描述。如果我们无法终止连接,这也会失败。


PostgreSQL 12 及更早版本中,当客户端连接到数据库时,您无法删除该数据库。

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

非常强大的解决方法如下:

超级用户身份连接到您的服务器,使用psql或其他客户端。千万不能使用你要删除的数据库。

psql -h localhost postgres postgres
Run Code Online (Sandbox Code Playgroud)

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

  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; */
    
    Run Code Online (Sandbox Code Playgroud)
  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'; */
    
    Run Code Online (Sandbox Code Playgroud)
  3. 删除数据库。

     DROP DATABASE mydb;
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 强行与你同在 (3认同)

小智 15

在我的案例中使用@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
Run Code Online (Sandbox Code Playgroud)


Erw*_*ter 12

Postgres的13增加了FORCE供选择DROP DATABASE。看filiprem 的回答

shell 实用程序dropdb基本上只是 SQL 命令的包装器,并继承了相同的选项。所以它现在从 shell 中也很简单可靠:

dropdb mydb --force
Run Code Online (Sandbox Code Playgroud)

或简短:

dropdb mydb -f
Run Code Online (Sandbox Code Playgroud)

对于Postgres 12 及更早版本,shell 实用程序dropdb& pg_ctl(或pg_ctlcluster在 Debian 和派生物中)也有一种方法。但filiprem 的方法那里优越有几个原因:

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

我引用man pg_ctlcluster

使用--force选项“快速”模式可回滚所有活动事务,立即断开客户端连接,从而彻底关闭。如果这不起作用,则会在“立即”模式下再次尝试关闭,这会使集群处于不一致状态,从而导致在下次启动时运行恢复。如果这仍然没有帮助,则 postmaster 进程将被终止。成功时以 0 退出,如果服务器未运行则以 2 退出,在其他失败情况下以 1 退出。此模式只应在机器即将关闭时使用。

pg_ctlcluster 9.1 main restart --force
Run Code Online (Sandbox Code Playgroud)

或者

pg_ctl restart -D datadir -m fast
Run Code Online (Sandbox Code Playgroud)

或者

pg_ctl restart -D datadir -m immediate
Run Code Online (Sandbox Code Playgroud)

紧随其后的是:

dropdb mydb
Run Code Online (Sandbox Code Playgroud)

可能在脚本中立即继承。

  • 这不仅不太理想,因为它启动了完整的 postgres 实例,而且不能保证它可以工作。客户端可能会在您重新启动服务器和尝试再次运行 dropdb 之间进行连接。@filiprem 上面的回答在断开连接之前禁用了与数据库的所有连接,并将保持其他数据库正常运行。 (4认同)