【问题标题】:How to release possible Postgres row locks?如何释放可能的 Postgres 行锁?
【发布时间】:2010-11-06 23:25:27
【问题描述】:

我通过 phpPgAdmin 界面在一个大型 PostgreSQL 表上运行了一条更新语句。由于运行时间过长而超时。

我现在可以更新该表中的一些行,但不是全部。尝试更新某些行会挂起。

行是否被锁定?如何允许更新这些行?

【问题讨论】:

    标签: sql database postgresql


    【解决方案1】:

    可以看到锁。

    这是一个比直接使用 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;
    

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

    SELECT * FROM active_locks;
    

    然后杀死它:

    SELECT pg_cancel_backend('%pid%');
    

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

    【讨论】:

    • Postgres 中没有名称为 active_locks 的视图或表。你的意思可能是pg_locks
    • 你说得对,我们的数据库中有一个自定义视图,我编辑了答案。
    • 就我而言,您的pg_cancel_backend 与此处的qeury 结合使用:stackoverflow.com/a/10317371/301277 允许我删除所有“被遗忘”的锁。谢谢!
    • 杀死类型“SELECT pg_cancel_backend(pid) FROM active_locks;”而是
    • 使用 "SELECT pg_terminate_backend('pid')" 强行杀死
    【解决方案2】:

    简单:

    从 pg_locks 获取活动锁:

    SELECT t.relname, l.locktype, page, virtualtransaction, pid, mode, granted
    FROM pg_locks l, pg_stat_all_tables t 
    WHERE l.relation = t.relid 
    ORDER BY relation asc;
    

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

    SELECT pg_terminate_backend(14210)
    

    【讨论】:

    • pg_cancel_backend(14210) 将取消带有 SIGINT 的查询与 SIGTERMdocumentation pg_terminate_backend(14210) 将终止会话以及查询。
    【解决方案3】:

    您运行的是哪个版本的 PostgreSQL?以下假设是 8.1.8 或更高版本(它可能也适用于早期版本,我不知道)。

    我认为您的意思是 phpPgAdmin 超时——PostgreSQL 后端将花费完成查询/更新所需的时间。在这种情况下,原始会话可能仍然存在并且 UPDATE 查询仍在运行。我建议在托管 PostgreSQL 服务器进程的机器上运行以下查询(取自 chapter 24 of the PostgreSQL docs),以查看会话是否仍然存在:

    ps auxwww|grep ^postgres
    

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

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

    如果您看到会话仍然存在,请将其终止。您需要以运行该进程的用户(通常是 postgres)或 root 身份登录 - 如果您自己不运行服务器,请让您的 DBA 为您执行此操作。

    还有一件事:为了更新表中的行,PostgreSQL 避免使用锁。相反,它允许每个写入事务创建一个新的数据库“版本”,当事务提交时,它成为“当前版本”,前提是它不与其他事务同时进行的更新发生冲突。所以我怀疑你看到的“挂起”是由其他原因引起的——虽然我不确定是什么。 (你有没有检查明显的东西,比如包含数据库的磁盘分区是否已满?)

    【讨论】:

    • 太好了,这行得通,谢谢。请注意,当我杀死导致问题的进程时,这允许其他一些等待释放锁的进程运行。这引起了一些进一步的问题。在终止第一个问题进程之前,我应该在运行 ps auxwww|grep ^postgres 时终止标记为“WAITING”的进程。
    • "如果您看到会话仍然存在,请将其终止。" -- 对于新手,看看上面写着postgres 15398 ... idle in transaction 或其他什么的地方,然后在Putty 中输入kill 15398
    【解决方案4】:

    为了从 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';
      
    2. 或者如果您可以通过运行此查询找出哪些进程在特定表上持有锁

      SELECT *
      FROM pg_locks l
      JOIN pg_class t ON l.relation = t.oid AND t.relkind = 'r'
      WHERE t.relname = 'Bill';
      
    3. 一旦您确定“活动”的 PID 并阻止您的更新,您就可以通过运行此查询来终止它。终止进程需要一些时间。

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

      SELECT pg_terminate_backend(__pid__);
      

    【讨论】:

      【解决方案5】:

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

      SELECT pg_terminate_backend(pid)
          FROM pg_stat_activity
          WHERE pid <> pg_backend_pid();
      

      【讨论】:

        【解决方案6】:

        我从未使用过 PostreSql,但如果它与其他类似,我会说你必须终止连接/结束持有锁的事务。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-01-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-05
          • 1970-01-01
          • 2018-12-19
          • 2016-07-22
          相关资源
          最近更新 更多