我需要编写一个脚本来删除一个PostgreSQL数据库。可能存在许多连接到该数据库的进程,但是脚本应忽略它们。
当存在打开的连接时,标准的DROP DATABASE db_name
查询将无法起作用。
我该如何解决这个问题?
我需要编写一个脚本来删除一个PostgreSQL数据库。可能存在许多连接到该数据库的进程,但是脚本应忽略它们。
当存在打开的连接时,标准的DROP DATABASE db_name
查询将无法起作用。
我该如何解决这个问题?
pg_stat_activity
并获取需要终止的进程id,然后针对它们执行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
。请参见此邮件列表线程。
; drop database TARGET_DB;
之前可以很好地确保数据库在重试开始时已经被删除了。 - Mat Schafferdropdb --force
支付费用。 - Torsten Bronger在 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
权限,否则用户将继续重新连接,而您将永远没有机会删除该数据库。请参见此评论和相关问题,如何从数据库中分离所有其他用户。
如果您只想断开空闲用户的连接,请参见此问题。
PostgreSQL 13引入了FORCE
选项。
DROP DATABASE删除一个数据库......此外,如果有其他人连接到目标数据库,则除非使用下面描述的FORCE选项,否则该命令将失败。
FORCE
试图终止所有现有连接到目标数据库的连接。如果在目标数据库中存在已准备好的事务、活动逻辑复制槽或订阅,则不会终止。
DROP DATABASE db_name WITH (FORCE);
易如反掌。
我只需在Ubuntu中重新启动服务即可断开已连接的客户端。
sudo service postgresql stop
sudo service postgresql start
psql
DROP DATABASE DB_NAME;
dropdb DB_NAME
无需进入postgres。 - Bicameral Minddropdb mydb --force
。 - devdrc你可以使用pg_terminate_backend(int)
函数在删除数据库之前终止所有连接。
您可以使用系统视图pg_stat_activity
获取所有正在运行的后台进程。
我不是完全确定,但以下操作可能会终止所有会话:
select pg_terminate_backend(procpid)
from pg_stat_activity
where datname = 'doomed_database'
当然,您可能没有连接到该数据库。根据你所使用的postgresql版本,你可能会遇到一个bug,使得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
。
我注意到Postgres 9.2现在将列名从procpid改为pid。
我倾向于从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。
PostgreSQL 9.2及以上版本:
SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'YOUR_DATABASE_NAME_HERE'
'YOUR_DATABASE_NAME_HERE'
替换为您要终止进程的数据库名称。这是我的黑客技巧... =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
sudo /etc/init.d/postgresql restart
bg
dropdb dbname
这对我在Linux命令提示符上有效。