PostgreSQL死锁排查与解决指南

 更新时间:2025年11月05日 09:56:21   作者:Moshow郑锴  
数据库死锁是后端开发者和DBA经常遇到的棘手问题,本文将手把手教你如何排查和解决PostgreSQL中的死锁问题,需要的朋友可以参考下

PostgreSQL 16默认会记录死锁吗?

答案是不会! 

虽然PostgreSQL 16具备死锁检测机制(在等待锁超过deadlock_timeout后会自动检测并解决死锁),但默认不会将死锁的详细信息记录到日志中。这就意味着你知道发生了死锁,却不知道具体原因!

如何配置死锁日志记录

1. 修改配置文件

找到PostgreSQL数据目录下的postgresql.conf文件,添加以下配置:

# 记录锁等待信息(关键!)
log_lock_waits = on
 
# 死锁检测超时时间(默认1秒)
deadlock_timeout = 1s
 
# 日志级别至少设置为log
log_min_messages = log
 
# 详细的日志前缀
log_line_prefix = '%t [%p]: db=%d,user=%u,app=%a,client=%h '

2. 重新加载配置

-- 在psql中执行
SELECT pg_reload_conf();

或者使用命令行:

pg_ctl reload -D /path/to/your/data/directory

死锁日志分析实例

配置完成后,当死锁发生时,你会在日志中看到类似这样的详细信息:

2025-11-02 10:23:41.123 CST [12345]: LOG:  📝 Powered by Moshow 郑锴 | 更多技术干货:https://zhengkai.blog.csdn.net
2025-11-02 10:23:41.123 CST [12345]: LOG:  process 12345 detected deadlock while waiting for ShareLock on transaction 123456 after 1000.123 ms
2025-11-02 10:23:41.123 CST [12345]: DETAIL:  Process holding the lock: 12346. Wait queue: .
2025-11-02 10:23:41.123 CST [12345]: PROCESS 12345: 等待事务 123456 的 ShareLock; 被进程 12346 阻塞.
2025-11-02 10:23:41.123 CST [12345]: PROCESS 12345: 执行语句: UPDATE accounts SET balance = balance - 100.00 WHERE user_id = 1;
2025-11-02 10:23:41.123 CST [12346]: PROCESS 12346: 等待事务 123457 的 ShareLock; 被进程 12345 阻塞.
2025-11-02 10:23:41.123 CST [12346]: PROCESS 12346: 执行语句: UPDATE accounts SET balance = balance + 50.00 WHERE user_id = 2;
2025-11-02 10:23:41.123 CST [12345]: ERROR:  deadlock detected

如何解读这个日志:

  • 涉及进程:进程12345和12346
  • 死锁场景:两个进程互相等待对方释放锁
  • 执行的SQL:两个UPDATE语句在竞争相同的资源
  • 解决方案:PostgreSQL选择中止进程12345的事务
    • 温和终止(优先尝试):     SELECT pg_terminate_backend(12345);
    • 强制终止(若温和方式失败):  SELECT pg_cancel_backend(12345);

实时监控:系统视图分析

除了查看日志,你还可以实时监控当前的锁等待情况:

强大的锁等待查询语句

--📝 Powered by Moshow 郑锴 | 更多技术干货:https://zhengkai.blog.csdn.net
SELECT
    blocked_locks.pid AS blocked_pid,
    blocked_activity.usename AS blocked_user,
    blocking_locks.pid AS blocking_pid,
    blocking_activity.usename AS blocking_user,
    blocked_activity.query AS blocked_statement,
    blocking_activity.query AS current_statement_in_blocking_process,
    blocked_activity.application_name AS blocked_application,
    blocking_activity.application_name AS blocking_application
FROM pg_catalog.pg_locks blocked_locks
JOIN pg_catalog.pg_stat_activity blocked_activity 
    ON blocked_activity.pid = blocked_locks.pid
JOIN pg_catalog.pg_locks blocking_locks 
    ON blocking_locks.locktype = blocked_locks.locktype
    AND blocking_locks.DATABASE IS NOT DISTINCT FROM blocked_locks.DATABASE
    AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
    AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
    AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
    AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
    AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
    AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
    AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
    AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
    AND blocking_locks.pid != blocked_locks.pid
JOIN pg_catalog.pg_stat_activity blocking_activity 
    ON blocking_activity.pid = blocking_locks.pid
WHERE NOT blocked_locks.granted;

查询结果示例:

blocked_pidblocked_userblocking_pidblocking_userblocked_statement
12345app_user12346app_userUPDATE accounts SET balance = balance - 100 WHERE user_id = 1
12347web_user12348batch_userDELETE FROM orders WHERE status = 'cancelled'

这个查询能帮你:

  • 实时发现阻塞情况
  • 识别阻塞的源头
  • 看到具体的阻塞SQL语句
  • 在死锁发生前进行干预

最佳实践建议

  • 生产环境务必配置日志:log_lock_waits = on 是你的生命线
  • 合理设置超时:deadlock_timeout 保持默认1秒即可
  • 定期检查日志:关注 pg_stat_database 中死锁计数器的变化
  • 代码层面预防:确保事务中的SQL操作顺序一致
  • 实时监控:使用系统视图查询作为辅助诊断工具

预防胜于治疗!通过合理的应用设计和数据库配置,可以大大减少死锁的发生频率。

以上就是PostgreSQL死锁排查与解决指南的详细内容,更多关于PostgreSQL死锁排查的资料请关注脚本之家其它相关文章!

相关文章

  • postgresql使用dblink跨库增删改查的步骤

    postgresql使用dblink跨库增删改查的步骤

    这篇文章主要介绍了postgresql使用dblink跨库增删改查,本文给大家介绍的非常详细对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • 查看postgresql数据库用户系统权限、对象权限的方法

    查看postgresql数据库用户系统权限、对象权限的方法

    这篇文章主要介绍了查看postgresql数据库用户系统权限、对象权限的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • postgresql13主从搭建Ubuntu

    postgresql13主从搭建Ubuntu

    这篇文章主要为大家介绍了postgresql13主从搭建Ubuntu实现过程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • PostgreSQL15.x安装的详细教程

    PostgreSQL15.x安装的详细教程

    PostgreSQL 是一个功能强大的开源关系型数据库系统,基于 C 语言实现,采用 PostgreSQL 许可证,这是一种自由软件许可证,允许用户自由使用、修改和分发源代码,所以本文将给大家介绍PostgreSQL15.x安装的详细教程,需要的朋友可以参考下
    2024-09-09
  • postgresql数据库配置文件postgresql.conf,pg_hba.conf,pg_ident.conf

    postgresql数据库配置文件postgresql.conf,pg_hba.conf,pg_ident.conf

    这篇文章主要为大家介绍了postgresql数据库中三个重要的配置文件postgresql.conf,pg_hba.conf,pg_ident.conf使用示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • 浅谈Postgresql默认端口5432你所不知道的一点

    浅谈Postgresql默认端口5432你所不知道的一点

    这篇文章主要介绍了浅谈Postgresql默认端口5432你所不知道的一点,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 15个postgresql数据库实用命令分享

    15个postgresql数据库实用命令分享

    这篇文章主要介绍了15个实用的postgresql数据库命令分享,都是一些技巧性的postgresql命令,需要的朋友可以参考下
    2014-07-07
  • PostgreSQL中enable、disable和validate外键约束的实例

    PostgreSQL中enable、disable和validate外键约束的实例

    这篇文章主要介绍了PostgreSQL中enable、disable和validate外键约束的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • CentOS中运行PostgreSQL需要修改的内核参数及配置脚本分享

    CentOS中运行PostgreSQL需要修改的内核参数及配置脚本分享

    这篇文章主要介绍了CentOS中运行PostgreSQL需要修改的内核参数及配置脚本分享,本文从系统资源限制类和内存参数优化类来进行说明,需要的朋友可以参考下
    2014-07-07
  • pgsql之create user与create role的区别介绍

    pgsql之create user与create role的区别介绍

    这篇文章主要介绍了pgsql之create user与create role的区别介绍,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01

最新评论