【问题标题】:How to drop a PostgreSQL database if there are active connections to it?如果有活动连接,如何删除 PostgreSQL 数据库?
【发布时间】:2011-07-21 11:00:03
【问题描述】:

我需要编写一个删除 PostgreSQL 数据库的脚本。可能有很多联系,但脚本应该忽略它。

当有打开的连接时,标准的DROP DATABASE db_name 查询不起作用。

我该如何解决这个问题?

【问题讨论】:

  • 你使用的是哪个版本的 PostgreSQL?
  • 问题:虽然您可能会终止连接到数据库的会话,但它们可能会很快重新连接,以至于您仍然无法删除数据库。令人高兴的是,这篇文章展示了如何锁定新连接,因此您可以按照计划终止当前连接并删除数据库:dba.stackexchange.com/questions/11893/…
  • 我在 dba.stackexchange 上发现这个答案非常有帮助 dba.stackexchange.com/a/11895/163539 -- 简洁但足够解释性。

标签: postgresql


【解决方案1】:

这将删除除您之外的现有连接:

查询 pg_stat_activity 并获取您要杀死的 pid 值,然后向它们发出 SELECT pg_terminate_backend(pid int)

PostgreSQL 9.2 及更高版本:

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 及以下:

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();

一旦您断开所有人的连接,您将必须断开连接并从来自另一个数据库的连接发出 DROP DATABASE 命令,该连接也不是您尝试删除的数据库。

注意将procpid 列重命名为pid。见this mailing list thread

【讨论】:

  • 当然,请务必从不是到“TARGET_DB”的连接的数据库连接中执行此操作,否则会出现“错误”。 “postgres”连接运行良好。
  • 其实它会一个一个断开客户端,如果你的客户端在列表中间,它也会断开。结果,一些连接将保持活动状态。所以,正确的答案是克雷格·林格(见下文)。选择 pg_terminate_backend(pg_stat_activity.pid) 从 pg_stat_activity WHERE datname = current_database() AND pg_stat_activity.pid pg_backend_pid();
  • 如何在他们完成当前事务后断开连接,然后删除有问题的表?
  • 在我的情况下,客户端会很快重新连接,因此将其放在 ; drop database TARGET_DB; 之前对我来说效果很好,以确保在事情开始重试时数据库已经消失。
  • 我什至愿意为dropdb --force付钱。
【解决方案2】:

在 PostgreSQL 9.2 及更高版本中,要断开除会话之外的所有内容与您连接的数据库的连接:

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

在旧版本中也是如此,只需将pid 更改为procpid。要断开与其他数据库的连接,只需将 current_database() 更改为您要断开用户连接的数据库的名称。

在断开用户连接之前,您可能希望从数据库用户那里直接REVOKE CONNECT,否则用户将继续重新连接,您将永远没有机会删除数据库。请参阅this comment 及其相关问题How do I detach all other users from the database

如果您只想断开空闲用户的连接,请参阅this question

【讨论】:

  • 从 pg_stat_activity 中选择 pg_terminate_backend(pg_stat_activity.pid) WHERE datname = current_database() AND pg_stat_activity.pid pg_backend_pid();
【解决方案3】:

PostgreSQL 13 引入了 FORCE 选项。

DROP DATABASE

DROP DATABASE 删除数据库...此外,如果其他人连接到目标数据库,此命令将失败,除非您使用 FORCE 选项如下所述。

原力

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

DROP DATABASE db_name WITH (FORCE);

【讨论】:

    【解决方案4】:

    简单易学。

    我只是在 Ubuntu 中重新启动服务以断开连接的客户端。

    sudo service postgresql stop
    sudo service postgresql start
    
    psql
    DROP DATABASE DB_NAME;
    

    【讨论】:

    • 这是过度工程。只需按下重置按钮。
    【解决方案5】:

    您可以使用pg_terminate_backend(int) 函数在删除数据库之前终止所有连接。

    您可以使用系统视图pg_stat_activity获取所有正在运行的后端

    我不完全确定,但以下可能会杀死所有会话:

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

    当然你自己可能没有连接到那个数据库

    【讨论】:

      【解决方案6】:

      根据您的 postgresql 版本,您可能会遇到一个错误,这会使pg_stat_activity 忽略掉线用户的活动连接。这些连接也没有在 pgAdminIII 中显示。

      如果您正在进行自动测试(在其中您还创建用户),这可能是一种可能的情况。

      在这种情况下,您需要恢复到以下查询:

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

      注意:在 9.2+ 中,您可以将 procpid 更改为 pid

      【讨论】:

      • 这就是我一直在寻找的,但是对于(假设 9.2 及更高版本)您必须删除对 pg_stat_activity 的引用并将 procpid 更改为 pid。
      • 在将 procpid 更改为 pid 后,此 sn-p 适用于 9.3。
      • 即使不删除 pg_stat_activity?我在 9.2 上遇到错误
      • 好的。现在我明白了,那是一个错字。谢谢!
      • 从 9.3 及以上版本 SELECT pg_terminate_backend(pid) FROM pg_stat_get_activity(NULL::integer) WHERE datid=(SELECT oid from pg_database where datname = 'your_database');
      【解决方案7】:

      我注意到 postgres 9.2 现在调用列 pid 而不是 procpid。

      我倾向于从 shell 调用它:

      #!/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
      

      希望对您有所帮助。感谢@JustBob 提供的sql。

      【讨论】:

        【解决方案8】:

        PostgreSQL 9.2 及更高版本:

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

        【讨论】:

        • 不会也终止活动连接吗?
        【解决方案9】:

        这是我的秘诀……=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>;"
        

        我提出这个答案是因为包含一个命令(上图)来阻止新连接,并且因为任何使用该命令的尝试...

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

        ...不能阻止新连接!

        感谢@araqnid @GoatWalker! =D

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

        【讨论】:

          【解决方案10】:

          在 Linux 命令提示符中,我将首先通过绑定此命令来停止所有正在运行的 postgresql 进程 sudo /etc/init.d/postgresql 重启

          输入命令 bg 检查其他 postgresql 进程是否仍在运行

          然后是 dropdb dbname 删除数据库

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

          这适用于我在 linux 命令提示符下

          【讨论】:

          • 如果您有许多数据库并且只想断开单个数据库的连接,这并不好。这将杀死所有连接。这有点“大锤”。
          • @Nick true 但请记住我们正在重新启动所有连接并完全停止它们
          【解决方案11】:

          在我的情况下,我必须执行一个命令来删除所有连接,包括我的活动管理员连接

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

          它终止了所有连接并向我显示致命的“错误”消息:

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

          之后就可以删除数据库了

          【讨论】:

            【解决方案12】:

            除了我使用 pgAdmin4 登录并在仪表板上我断开了除 pgAdmin4 之外的所有连接之外,没有什么对我有用,然后能够通过右键单击数据库和属性并输入新名称来重命名。

            【讨论】:

              【解决方案13】:

              在 Windows 上,您可以打开任务管理器 -> 服务,找到“postgresql”进程,然后重新启动它。当服务再次运行时,可以删除数据库。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2010-10-02
                • 1970-01-01
                • 2011-03-20
                • 2013-07-01
                • 2020-05-04
                • 2017-08-18
                • 2014-07-29
                相关资源
                最近更新 更多