PostgreSQL 删除表无效

49

我正在尝试使用“DROP TABLE”命令删除一些表,但出于未知原因,程序只是“停滞”,无法在数据库中删除我想要的表。

我的数据库中有3个表:

Product(产品)、Bill(账单)和Bill_Products(用于引用账单中的产品)。

我已经成功删除/丢弃了Product表,但我无法对不同的Bill和Bill_Products表进行相同的操作。 我发出了相同的“DROP TABLE Bill CASCADE;”命令,但命令行却一直处于停顿状态。 我还使用了不带“CASCADE”选项的简单版本。

你有任何想法是为什么会发生这种情况吗?

更新:

我一直在思考可能是由于数据库中保留了一些从产品到账单的引用,这就是为什么它无法删除Bill表。

因此,为此目的,我发出了一个简单的“SELECT * from Bill_Products”命令,大约过了10-15秒钟(奇怪的是,因为空表不应该需要这么长时间),它打印出了表及其内容,但其中没有内容。(因此显然从产品到账单已经没有引用了。)


1
命令行就是卡住了。这是什么意思?psql 崩溃、挂起或冻结了吗?你必须杀掉它吗?Ctrl-C 是什么作用?我想我只是在说“卡住”是什么意思。或者你没有使用 psql? - alan
3
也许另一个事务锁定了这个表,所以你不能删除它? - wildplasser
好主意。我认为“重新启动”可以解决它,对吗? - Radu Gheorghiu
1
重启只适用于名为“Bill”的表格;-) - wildplasser
@wildplasser,已经过去3年了,现在我才明白你的“Bill”表笑话。真不错! - Radu Gheorghiu
显示剩余9条评论
8个回答

71

输出结果是什么?

SELECT *
  FROM pg_locks l
  JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r'
 WHERE t.relname = 'Bill';

可能有其他会话并行使用您的表,您无法获取独占访问锁以删除它。


1
psdemo=> SELECT * from pg_locks l join pg_class t on l.relation = t.oid AND t.relkind = 'r' WHERE t.relname="ps_bill"; ERROR: column "ps_bill" does not exist LINE 1: ...ation = t.oid AND t.relkind = 'r' WHERE t.relname="ps_bill"; - Radu Gheorghiu
对于字面值,请使用单引号(撇号)。PostgreSQL符合SQL标准,将双引号视为包装标识符 - kgrittn
2
谢谢你,但我通过简单的重启解决了它。我所做的有点傻,也不是什么神秘的事情,但这是解决问题的最短途径。我给你的答案点赞,以表达我的感激之情。我想确实有一个事务锁定了表格。 - Radu Gheorghiu
2
是的,我成功地通过简单地重新启动postgresql并删除表来解决了这个问题。 - Madhu V Rao

27

只需要做

SELECT pid, relname
FROM pg_locks l
JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r'
WHERE t.relname = 'Bill';

然后通过以下命令杀死所有pid:

kill 1234

在查询结果中,1234是实际pid。

您可以将它们全部连接起来,像这样(这样您就不必手动复制每个pid):

psql -c "SELECT pid FROM pg_locks l 
    JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r' 
    WHERE t.relname = 'Bill';" | tail -n +3 | head -n -2 | xargs kill

即使我发布这个问题已经超过3年了,我仍然想感谢你的到来并分享你的解决方案。但是,我的问题是relname是什么? - Radu Gheorghiu
1
@RaduGheorghiu的relname实际上是一个表名。 - chemikadze

13
如果这是针对AWS postgres的话,运行第一个语句以获取PID(进程ID),然后运行第二个查询来终止该进程(与kill -9非常相似,但由于这是在云中,AWS建议使用此方法)。
-- gets you the PID
SELECT pid, relname FROM pg_locks l JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r' WHERE t.relname = 'YOUR_TABLE_NAME'

-- what actually kills the PID ...it is select statement but it kills the job!
SELECT pg_terminate_backend(YOUR_PID_FROM_PREVIOUS_QUERY);

source


11

我曾经花了几个小时碰壁,试图解决同样的问题,这是对我有效的解决方法:

检查PostgreSQL是否有尚未提交或回滚的待处理事务:

SELECT database, gid FROM pg_prepared_xacts;
如果您得到了结果,那么对于每个事务中的gid,您必须从出现问题的数据库执行一个ROLLBACK
ROLLBACK PREPARED 'the_gid';

欲了解更多信息,请点击这里


7
今天我遇到了这个问题,我执行了以下命令:
DROP TABLE TableNameHere 然后出现错误:ERROR: table "tablenamehere" does not exist。我意识到对于大小写敏感的表(就像我的表一样),你需要用引号引起来:
DROP TABLE "TableNameHere"

5

我遇到了同样的问题。

这个表上没有任何锁。

重新启动解决了问题。


2
对我来说也一样。我不需要重新启动,只需要重新启动postgresql即可。 - John Sampson

3

我也遇到了同样的问题——只不过是因为我忘记了分号。摊手


哦,你救了我。我一直在想为什么即使我拼错了表名也没有收到消息。现在一切都说得通了。谢谢! - Alexandru DuDu
哇,你救了我。我一直在想为什么即使我拼错了表名字也没有收到消息。现在一切都清楚了。谢谢你! - Alexandru DuDu

2

虽然这是一个老问题,但我遇到了类似的问题。无法重新启动数据库,因此尝试了几个方法,直到使用以下步骤才成功:

  • 截断表 foo;
  • 并发删除索引 foo_something;重复 4-5 次
  • 三次删除外键列 whatever_foreign_key;
  • 删除列 id;
  • 删除表 foo。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接