PostgreSQL非关联表间死锁问题排查及技术疑问
2022-10-12 20:23:27 KST [40P01] [11983 (4)] ... ERROR: deadlock detected 2022-10-12 20:23:27 KST [40P01] [11983 (5)] ... DETAIL: Process 11983 waits for ShareLock on transaction 12179793; blocked by process 11893. Process 11893 waits for ShareLock on transaction 12179803; blocked by process 12027. Process 12027 waits for ExclusiveLock on tuple (1881,5) of relation 17109 of database 16384; blocked by process 11983. Process 11983: update B set ... where id=$1 Process 11893: update A set ... where a=$1 and b=$2 Process 12027: update B set ... where id=$1 2022-10-12 20:23:27 KST [40P01] [11983 (6)] ... HINT: See server log for query details. 2022-10-12 20:23:27 KST [40P01] [11983 (7)] ... CONTEXT: while locking tuple (1881,5) in relation "B" 2022-10-12 20:23:27 KST [40P01] [11983 (8)] ... STATEMENT: update B set ... where id=$1
PostgreSQL死锁疑问解答
1. 进程11983为何等待进程11893?
根据日志DETAIL部分,进程11983在等待事务12179793上的ShareLock,而这个锁被进程11893持有。这里的ShareLock属于事务ID锁,用于避免并发事务间的可见性冲突(比如快照过旧、事务ID回卷问题)。
进程11893执行表A的更新时,会持有自身事务ID(12179793)的ShareLock;进程11983执行表B的更新时,需要获取该事务ID的ShareLock来确认事务状态,因此被进程11893阻塞。
2. 进程12027执行update语句时是否会使用ShareLock?
Update语句核心操作会对目标元组加ExclusiveLock(排他锁),但会间接涉及ShareLock:
- PostgreSQL在验证事务ID有效性时,会持有自身事务ID的ShareLock,这也是进程11893等待进程12027的原因。
- 若update的where子句扫描阶段需要确认其他事务状态,也可能临时申请事务ID的ShareLock,但元组修改本身不会用ShareLock。
所以进程12027执行update时,不会主动申请元组的ShareLock,但会持有自身事务ID的ShareLock。
3. 如何查询tuple(1881,5)对应的实际数据?
按以下步骤操作:
步骤1:确认元组所属表(可选,已明确是表B)
日志中relation 17109是表的OID,执行语句验证表名:
SELECT relname FROM pg_class WHERE oid = 17109;
步骤2:查询元组数据
PostgreSQL用ctid标识元组,格式为(块号, 元组序号),直接查询表B中对应ctid的数据:
SELECT * FROM "B" WHERE ctid = '(1881,5)';
注意:如果元组已被删除或清理,可能需要通过表的备份或历史快照查询,未清理前ctid有效。
内容的提问来源于stack exchange,提问作者DongHoon Kim
相关产品推荐
相关产品推荐

