Det finns ingen bugg, och jag tror inte att du missförstår någonting; du saknar bara ett par pusselbitar.
Främmande nycklar implementeras internt med låsning på radnivå; från Postgres 8.1 och upp till 9.2, närhelst du uppdaterar referenstabellen (apples
i det här fallet) aktiveras en fråga som gör SELECT FOR SHARE
i den refererade tabellen (trees
). Så att SELECT FOR UPDATE
i den första transaktionen blockerar SELECT FOR SHARE
av referensintegriteten för den andra transaktionen. Det är detta som orsakar blockeringen i det andra kommandot.
Nu hör jag dig skrika:"Vänta! Hur kommer det sig att det blockerar det andra kommandot och inte det första? Förklaringen är egentligen enkel -- det är bara för att det finns en enkel optimering som hoppar över den interna SELECT FOR SHARE
när nyckeln inte ändras. Detta är dock förenklat genom att om du uppdaterar en tuppel en andra gång, kommer denna optimering inte att aktiveras eftersom det är svårare att spåra de ursprungliga värdena. Därav blockeringen.
Du kanske också undrar varför jag sa att detta är upp till 9,2 --- vad är det med 9,3? Den största skillnaden där är att den i 9.3 använder SELECT FOR KEY SHARE
, som är en ny, lättare låsnivå; det möjliggör bättre samtidighet. Om du provar ditt exempel i 9.3 och även ändrar SELECT FOR UPDATE
till SELECT FOR NO KEY UPDATE
(vilket är ett lättare läge än SELECT FOR UPDATE
som säger att du kanske kommer att uppdatera tupeln, men du lovar att inte ändra primärnyckeln och lovar att inte ta bort den), bör du se att den inte blockeras. (Du kan också prova en UPPDATERING på den refererade raden och om du inte ändrar primärnyckeln kommer den inte heller att blockeras.)
Den här 9.3-grejen introducerades av en patch av yours truly som http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0ac5ad5134f2769ccbaefec73844f8504c4d6182 och jag tycker att det var ett ganska coolt hack (commit-meddelandet har några fler detaljer, om du bryr dig om den typen av saker). Men se upp, använd inte versioner före 9.3.4 eftersom den patchen var så enormt komplex att några allvarliga buggar försvann och vi fixade det först nyligen.