【问题标题】:Terminate hung query (idle in transaction)终止挂起的查询(在事务中空闲)
【发布时间】:2022-05-13 04:43:02
【问题描述】:

我正在使用带有 Crane Postgres 选项的 Heroku,当我的本地计算机崩溃时,我正在从本地计算机上运行数据库查询。如果我运行

select * from pg_stat_activity

其中一个条目有

<IDLE> in transaction

在 current_query_text 列中。

因此,我无法删除已终止的查询正在写入的表。我曾尝试使用 pg_cancel_backend(N) 并返回 True 但似乎没有任何反应。

我怎样才能终止这个过程以便我可以删除表?

【问题讨论】:

  • 也许问题应该改写为“当我既没有对 postgres 服务器的 root 访问权限,也没有对数据库的超级用户访问权限时,我如何终止我自己的查询”。这似乎确实是一个非常好的问题......我不知道答案。

标签: postgresql


【解决方案1】:

这是一个通用的 Postgres 答案,并不特定于 heroku


(这个问题的简单愚蠢的答案可能是......只需重新启动 postgresql。假设这是不可取的或不是一个选项......)

通过运行此 sql 查找 PID:

SELECT pid , query, * from pg_stat_activity
  WHERE state != 'idle' ORDER BY xact_start;

(查询可能需要根据 postgres 的版本进行修改 - 最终,只需从 pg_stat_activity 中选择 *)。您会在第一(左)列中找到 pid,第一(顶)行可能是您想要终止的查询。我假设下面的 pid 是 1234。

您可以通过 SQL 取消查询(即没有 shell 访问权限),只要它是您的或您具有超级用户访问权限:

select pg_cancel_backend(1234);

这是取消 1234 查询的“友好”请求,如果运气好的话,它会在一段时间后消失。如果需要,以下更像是一个“硬终止”命令,可能会导致它更快地取消:

select pg_terminate_backend(1234);

如果您有 shell 访问权限和 root 或 postgres 权限,您也可以从 shell 执行此操作。要“取消”,可以这样做:

kill -INT 1234

而“终止”,简单地说:

kill 1234

不要:

kill -9 1234

...这通常会导致整个postgres服务器陷入困境,那么您不妨重新启动postgres。 Postgres 非常健壮,因此数据不会被破坏,但我建议在任何情况下都不要使用“kill -9”:-)


长期的“事务空闲”通常意味着事务没有因“提交”或“回滚”而终止,这意味着应用程序存在错误或未正确设计为与事务数据库一起使用。应避免长时间的“事务空闲”,因为它也可能导致严重的性能问题。

【讨论】:

  • 我试过 pg_cancel_backend 无济于事。我没有 shell 访问权限,也不是超级用户,所以我无法使用 pg_terminate_backend 发送 SIGKILL
  • 您使用的是哪个版本的 postgres? (提示:select version())。使用pg_cancel_backend 时是否收到任何错误消息?
  • 自己尝试使用 pg_cancel_backend,所以收到错误消息“必须是超级用户才能向其他服务器进程发出信号”......这意味着您显然需要服务器上的 root 访问权限或通过 db 访问一些 postgres 超级用户(即 postgres 用户)来终止您自己的查询。这似乎有点糟糕:-(
  • 原来进程被 pg_cancel_backend 取消了,但是查询仍然在 pg_stat_activity 中显示一段时间
  • 也许它是 Heroku 特有的。据我所见,在普通 postgres 下,确实需要超级用户才能杀死卡住的进程(我正在使用 pg 8.4 上的“select pg_sleep(3600);”进行测试,我得到“错误:必须是超级用户才能发出信号其他服务器进程”)。不过,“交易中的空闲”又不完全一样。
【解决方案2】:

试试这个:

select pg_terminate_backend(pid int)

更多相关信息,您可以找到here。这应该是比系统杀死进程更“干净”的解决方案。

【讨论】:

  • 请添加如何让您的 pid 到您的答案
【解决方案3】:

您可以安装heroku-pg-extras 插件并运行以下命令来获取PID:

heroku pg:locks --app <your-app>

那就这样吧:

heroku pg:kill <pid> --app <your-app> 

注意--force 选项可用于发出 pg_terminate_backend 以断开该查询的整个连接。

如果heroku pg:locks 没有列出任何内容,请尝试heroku pg:ps

欲了解更多信息,请查看:
https://devcenter.heroku.com/articles/heroku-postgresql#pg-ps-pg-kill-pg-killall

【讨论】:

  • 谢谢。我仍然无法终止事务/PID……我的计算机在导入期间发生了硬件冻结,我无法终止 PID。 :(
【解决方案4】:

终止所有正在运行的查询:

SELECT pg_cancel_backend(pid) FROM pg_stat_activity WHERE state = 'active'; 

来自here

【讨论】:

    猜你喜欢
    • 2015-06-22
    • 1970-01-01
    • 2018-04-27
    • 2011-05-16
    • 2012-03-07
    • 1970-01-01
    • 2021-11-16
    • 2020-04-04
    相关资源
    最近更新 更多