Postgres deadlock

梦想与她 提交于 2019-12-11 08:59:51

问题


I am seeing some unexplained deadlocks in our Postgres database. Simplifying the related queries, one of the transactions involved in the deadlock is:

BEGIN;
UPDATE A SET CHUNK_ID=1, STATUS='PROCESSING' WHERE ID IN (
    SELECT ID FROM A
    WHERE CHUNK_ID IS NULL
    ORDER BY O_ID
    LIMIT 1000
    FOR UPDATE 
);
COMMIT;

and the other one is:

BEGIN;
UPDATE A SET STATUS='SENT' WHERE ID = 1; 
UPDATE A SET STATUS='SENT' WHERE ID = 2;
UPDATE A SET STATUS='SENT' WHERE ID = 3;
...
COMMIT; 

My question is how is it possible to have a deadlock here? I cannot think of any scenario where the 1st transaction can result to a deadlock, regardless of any other query running at the same time.

Is there any such case, i.e. an UPDATE using a nested SELECT ... FOR UPDATE can be part of a deadlock?

Thanks


回答1:


(This is a conjecture, but hopefully an educated one.)

Everything hinges on the order in which rows are locked by the SELECT ... ORDER BY O_ID ... FOR UPDATE. If the order of O_ID is different from the order of ID, then it is perfectly possible to have a situation similar to this:

ID    O_ID
--    ----
1     2
2     1
  • Transaction A locks the row with ID=2.
  • Transaction B locks the row with ID=1.
  • Transaction A tries to lock the row with ID=1, but is forced to wait on transaction B.
  • Transaction B tries to lock the row with ID=2, but is forced to wait on transaction A.

WARNING: Even if the O_ID order is the same as the ID order, it is possible that the ORDER BY clause doesn't actually guarantee the order of locking (it just guarantees the order in which the results are returned). Unfortunately, this seems poorly documented. For what it's worth, it appears Oracle doesn't (always) honor ORDER BY when it comes to locking, so I'd be careful under PostgreSQL as well.

Generally, the solution to deadlocks is to always lock in the same order. Assuming the ORDER BY actually guarantees the order of locking, you could simply include SELECT ... ORDER BY O_ID ... FOR UPDATE in the second transaction. Or alternatively, use ORDER BY ID in the first transaction.

BTW, why are you explicitly locking in the first place? What exactly are you trying to accomplish with that?



来源:https://stackoverflow.com/questions/14964616/postgres-deadlock

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!