我们注意到下列情况一个PostgreSQL 9.2服务器上的僵局的一种罕见的发生:Postgres的僵局read_commited隔离
T1开始批量操作:
UPDATE BB bb SET status = 'PROCESSING', chunk_id = 0 WHERE bb.status ='PENDING'
AND bb.bulk_id = 1 AND bb.user_id IN (SELECT user_id FROM BB WHERE bulk_id = 1
AND chunk_id IS NULL AND status ='PENDING' LIMIT 2000)
当T1后几犯几百毫秒左右(BB有几百万行),多线程开始从BB阅读项目新交易(每线程一个交易),做一些处理,并与查询,更新他们的50个左右的批次:
对于选择:
SELECT *, RANK() as rno OVER(ORDER BY user_id) FROM BB WHERE status = 'PROCESSING' AND bulk_id = 1 and rno = $1
和更新:
UPDATE BB set datetime=$1, status='DONE', message_id=$2 WHERE bulk_id=1 AND user_id=$3
(USER_ID,bulk_id唯一性约束)。
由于状况问题的外部原因,另一个事务T2几乎在T1已经提交之后执行与T1相同的查询(初始批处理操作,其中项目被标记为'PROCESSING')。
UPDATE BB bb SET status = 'PROCESSING', chunk_id = 0 WHERE bb.status ='PENDING'
AND bb.bulk_id = 1 AND bb.user_id IN (SELECT user_id FROM BB WHERE bulk_id = 1
AND chunk_id IS NULL AND status ='PENDING' LIMIT 2000)
然而,尽管这些项目被标记为“处理中”此查询死锁与一些更新(这是分批正如我所说所做)关闭工作线程。据我的理解,这不应该发生在我们使用的READ_COMMITTED隔离级别(默认)上。我确信T1已经提交,因为工作线程在完成之后执行。
编辑:我应该清楚的一件事是T2开始后T1但提交之前。然而,由于我们在同一行(不受任何上述查询影响)上使用SELECT for UPDATE
获取的write_exclusive元组锁,它在运行批量更新查询之前等待T1提交。