PostgreSQL死锁如何排查定位?详细诊断流程是什么

来源:站长论坛作者:小菜鸟头衔:草根站长
导读:本期聚焦于小伙伴创作的《PostgreSQL死锁如何排查定位?详细诊断流程是什么》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《PostgreSQL死锁如何排查定位?详细诊断流程是什么》有用,将其分享出去将是对创作者最好的鼓励。

PostgreSQL的死锁是指两个或多个事务互相持有对方需要的锁,且都在等待对方释放锁,导致所有相关事务都无法继续执行的情况。死锁发生后PostgreSQL会自动检测并终止其中一个事务,返回死锁错误,但我们需要定位具体原因避免问题重复出现。

PostgreSQL死锁如何排查定位?详细诊断流程是什么

死锁产生的常见原因

PostgreSQL的死锁大多和事务执行顺序、锁类型冲突有关,常见场景包括:

  • 多个事务以不同顺序更新同一批数据,比如事务A先更新表1再更新表2,事务B先更新表2再更新表1
  • 长事务持有锁时间过长,阻塞了其他事务的锁请求
  • 对大表执行全表更新时,锁范围覆盖过广,和其他小事务的锁产生冲突
  • 索引缺失导致更新操作触发表锁升级,和其他行级锁冲突

死锁排查定位完整流程

第一步:查看数据库死锁日志

PostgreSQL默认会把死锁相关信息记录到日志中,首先可以查看数据库日志定位基础信息。日志中会出现deadlock detected关键字,包含死锁涉及的事务ID、等待的锁类型、相关SQL片段。如果是Linux环境,可以通过以下命令快速筛选死锁日志:

grep "deadlock detected" /var/log/postgresql/postgresql-14-main.log

日志中典型死锁内容示例如下:

2024-05-10 14:23:10 CST [12345] ERROR:  deadlock detected
2024-05-10 14:23:10 CST [12345] DETAIL:  Process 12345 waits for ShareLock on transaction 67890; blocked by process 54321.
Process 54321 waits for ShareLock on transaction 12345; blocked by process 12345.
Process 12345: UPDATE user_info SET balance = balance - 100 WHERE id = 1;
Process 54321: UPDATE user_info SET balance = balance + 100 WHERE id = 2;

第二步:查询实时活跃会话信息

如果死锁正在发生,可以通过pg_stat_activity系统视图查询当前所有活跃会话的状态,定位阻塞关系。执行以下SQL可以查看当前等待锁的会话:

SELECT 
    pid, 
    usename, 
    datname, 
    query, 
    state, 
    wait_event_type, 
    wait_event, 
    now() - query_start AS query_duration
FROM pg_stat_activity 
WHERE wait_event_type = 'Lock' 
ORDER BY query_start ASC;

结果中wait_event_type为Lock的会话就是正在等待锁的会话,query字段是对应的执行SQL,pid是会话进程ID。如果要查看某个会话被哪个会话阻塞,可以结合pg_locks视图查询:

SELECT 
    a.pid AS blocked_pid,
    a.usename AS blocked_user,
    a.query AS blocked_query,
    b.pid AS blocking_pid,
    b.usename AS blocking_user,
    b.query AS blocking_query
FROM pg_stat_activity a
JOIN pg_locks l1 ON a.pid = l1.pid AND NOT l1.granted
JOIN pg_locks l2 ON l1.locktype = l2.locktype 
    AND l1.database IS NOT DISTINCT FROM l2.database
    AND l1.relation IS NOT DISTINCT FROM l2.relation
    AND l1.page IS NOT DISTINCT FROM l2.page
    AND l1.tuple IS NOT DISTINCT FROM l2.tuple
    AND l1.virtualxid IS NOT DISTINCT FROM l2.virtualxid
    AND l1.transactionid IS NOT DISTINCT FROM l2.transactionid
    AND l2.granted
JOIN pg_stat_activity b ON b.pid = l2.pid
WHERE a.wait_event_type = 'Lock';

第三步:定位具体死锁事务和SQL

结合日志中的事务ID和实时会话的PID,可以定位到具体的死锁SQL。如果需要终止阻塞的会话,可以使用pg_terminate_backend函数,注意优先终止执行时间更长、影响范围更小的会话:

-- 终止PID为54321的会话,替换为实际查询到的阻塞会话PID
SELECT pg_terminate_backend(54321);

第四步:复现和分析死锁根因

拿到死锁相关的SQL后,需要分析事务的执行顺序和锁类型。可以通过EXPLAIN分析SQL的执行计划,确认是否触发表锁、是否走了正确的索引。如果是执行顺序导致的死锁,可以调整事务中SQL的执行顺序,保证所有事务都按照相同的顺序操作数据。

避免PostgreSQL死锁的实用建议

  • 尽量缩短事务的执行时间,避免长事务持有锁过久
  • 所有事务按照统一的顺序访问表和行数据,避免交叉加锁
  • 为更新操作涉及的字段添加合适的索引,避免全表扫描触发表锁升级
  • 更新数据时尽量指定具体的行范围,减少锁的覆盖范围
  • 可以设置合理的lock_timeout参数,避免事务无限等待锁

总结

PostgreSQL死锁的排查定位核心是先通过日志获取基础信息,再通过系统视图查询实时会话的锁等待关系,最终定位到具体的SQL和事务。日常开发中遵循统一的操作顺序、控制事务时长,可以有效减少死锁的发生概率。如果遇到复杂死锁问题,还可以开启log_lock_waits参数,记录更详细的锁等待信息辅助排查。

PostgreSQL死锁排查死锁诊断pg_stat_activity修改时间:2026-06-18 06:48:21

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。