如何释放可能的Postgres行锁?

Lia*_*iam 35 sql database postgresql

我通过phpPgAdmin接口在大型PostgreSQL表上运行了更新语句.因为它运行了太长时间.

我现在可以更新该表中的某些行但不是全部.尝试更新某些行将挂起.

行被锁定了吗?如何允许更新这些行?

Chr*_*ris 80

可以看到锁.

这是一个使直接使用pg_locks更容易的视图:

CREATE OR REPLACE VIEW public.active_locks AS 
 SELECT t.schemaname,
    t.relname,
    l.locktype,
    l.page,
    l.virtualtransaction,
    l.pid,
    l.mode,
    l.granted
   FROM pg_locks l
   JOIN pg_stat_all_tables t ON l.relation = t.relid
  WHERE t.schemaname <> 'pg_toast'::name AND t.schemaname <> 'pg_catalog'::name
  ORDER BY t.schemaname, t.relname;
Run Code Online (Sandbox Code Playgroud)

然后你只需从视图中选择:

SELECT * FROM active_locks;
Run Code Online (Sandbox Code Playgroud)

用以下方法杀死它:

SELECT pg_cancel_backend('%pid%');
Run Code Online (Sandbox Code Playgroud)

其他解决方案:http: //wiki.postgresql.org/wiki/Lock_Monitoring

  • 使用"SELECT pg_terminate_backend('pid')"强行杀死 (6认同)
  • Postgres中没有名为`active_locks`的视图或表.你是说'pg_locks`吗? (3认同)
  • 杀死类型"SELECT pg_cancel_backend(pid)FROM active_locks;" 代替 (3认同)

j_r*_*ker 21

您运行的是什么版本的PostgreSQL?以下假定为8.1.8或更高版本(它也可能适用于早期版本,我不知道).

我认为你的意思是phpPgAdmin超时 - PostgreSQL后端将花费很长时间来完成查询/更新.在这种情况下,原始会话可能仍然存在且UPDATE查询仍在运行.我建议在托管PostgreSQL服务器进程的机器上运行以下查询(取自PostgreSQL文档的第24章),以查看会话是否仍然存在:

ps auxwww|grep ^postgres
Run Code Online (Sandbox Code Playgroud)

应该出现几行:1表示postmaster主进程,1表示"writer","stats buffer"和"stats collector"进程.任何剩余行都用于为DB连接提供服务的进程.这些行将包含用户名和数据库名称.

希望您可以看到您执行原始UPDATE的会话是否仍然存在.虽然理论上你可以SELECT从系统视图中找到更详细的信息pg_stat_activity,但默认情况下PostgreSQL没有设置为填充最有用的字段(例如current_queryquery_start).有关如何在将来启用此功能,请参阅第24章.

如果您看到会话仍在那里,请将其删除.您需要以运行流程的用户(通常postgres)或root身份登录才能执行此操作 - 如果您不自行运行服务器,请让DBA为您执行此操作.

还有一件事:为了更新表中的行,PostgreSQL避免使用锁.相反,它允许每个写入事务创建数据库的新"版本",在事务提交时成为"当前版本",前提是它与其他事务同时进行的更新不冲突.所以我怀疑你所看到的"悬挂"是由其他东西造成的 - 尽管如此,我不确定.(您是否检查了明显的事情,例如包含数据库的磁盘分区是否已满?)

  • "如果你看到会话还在那里,就把它杀掉吧." - 对于新手来说,看看它说`postgres 15398 ...在交易中闲置'或者什么,在Putty中输入`kill 15398`. (2认同)

小智 17

简单:

从pg_locks获取活动锁:

选择t.relname,l.locktype,page,virtualtransaction,pid,mode,授予pg_locks l,pg_stat_all_tables t其中l.relation = t.relid order by relation asc;

从上面的结果中复制pid(例如:14210)并替换为以下命令.

SELECT pg_terminate_backend('14210')

  • `pg_cancel_backend(14210)` 将使用 `SIGINT` 与 `SIGTERM` 取消查询,[文档](https://www.postgresql.org/docs/current/functions-admin.html) `pg_terminate_backend(14210) ` 将终止会话和查询。 (3认同)

Sau*_*aha 6

要从Postgres释放可能的锁,我通常会依次执行。

  1. 通过运行以下查询,在数据库中查找长期运行的查询。这将帮助您获取长时间运行的查询的PID,这会阻止您的更新。

    SELECT
    pid,
    now() - pg_stat_activity.query_start AS duration,
    query,
    state
    FROM pg_stat_activity
    WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes';
    
    Run Code Online (Sandbox Code Playgroud)
  2. 或者是否可以通过运行此查询找出哪些进程在特定表上持有锁

    SELECT *
    FROM pg_locks l
    JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r'
    WHERE t.relname = 'Bill';
    
    Run Code Online (Sandbox Code Playgroud)
  3. 一旦找出了“活动”的PID并阻止了更新,就可以通过运行此查询将其终止。需要花费一些时间来终止该过程。

    SELECT pg_cancel_backend(__pid__);
    
    Run Code Online (Sandbox Code Playgroud)
  4. 通过运行查询2来检查进程是否被终止。如果它仍然处于活动状态,则通过运行此查询来终止该过程。

    SELECT pg_terminate_backend(__pid__);
    
    Run Code Online (Sandbox Code Playgroud)


Jak*_*ski 6

这将清除所有表上的所有锁。

SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE pid <> pg_backend_pid();
Run Code Online (Sandbox Code Playgroud)