PostgreSQL进程互锁未检测及ShareLock异常使用问题咨询
问题解答
1. 进程互相阻塞未被检测为死锁的原因及存储过程的影响
PostgreSQL的死锁检测逻辑是:当进程等待锁的时长超过deadlock_timeout(此处为1s)时,会主动遍历锁等待图,查找是否存在循环依赖的等待关系。未被检测为死锁的可能原因如下:
- 等待关系并非严格循环:若通过
pg_locks查询时遗漏了第三方进程,可能误判为两进程互相等待,实际是二者都在等待第三方持有的锁,此时不存在循环依赖,死锁检测不会触发。 - 锁兼容特性导致无真正死锁:ShareLock与其他ShareLock是兼容的,不会互相阻塞。若两进程都处于等待ShareLock的状态,实际大概率是二者都在等待某个ExclusiveLock(如其他事务的写锁),并非互相等待对方的ShareLock。
- 存储过程的潜在影响:
- 若存储过程中使用了自治事务,自治事务的锁独立于主事务,死锁检测无法关联主事务与自治事务的锁等待链,导致循环依赖未被识别。
- 若存储过程内存在嵌套子事务,子事务持有的锁与主事务的锁在等待图中未被正确关联,可能导致死锁检测遗漏循环。
- 锁请求时序问题:若进程A先等待进程B的锁,死锁检测触发时进程B尚未发起对进程A锁的请求;之后进程B才发起锁请求形成循环,但此时进程A的等待已超过
deadlock_timeout,不会再次触发检测,导致死锁未被发现。
2. 非索引操作场景下出现ShareLock的原因
ShareLock的应用场景远不止CREATE INDEX这类索引操作,以下常见操作都会触发ShareLock:
- 行级锁查询:使用
SELECT ... FOR SHARE或SELECT ... FOR UPDATE SKIP LOCKED语句时,会对命中的行(或无索引时对全表)申请ShareLock。 - 表结构变更:部分
ALTER TABLE操作(如ALTER TABLE ... SET TABLESPACE、添加带非空默认值的列)会申请表级ShareLock。 - 全量清理操作:
VACUUM FULL会对目标表申请ShareLock,阻止其他写事务。 - 显式锁表:业务代码或存储过程中若调用
LOCK TABLE ... IN SHARE MODE,会直接申请表级ShareLock。 - 统计信息收集:
ANALYZE命令在对大表执行时,可能会申请ShareLock以保证统计数据的一致性。 - 备份操作:如
pg_dump在备份过程中,若未指定--no-lock参数,会对目标表申请ShareLock以确保备份数据的一致性。
内容的提问来源于stack exchange,提问作者xoip
相关产品推荐
相关产品推荐

