Bug in PostgreSQL locking mechanism or misunderstanding of the mechanism

放肆的年华 提交于 2019-12-05 02:58:08

There is no bug, and I don't think you're misunderstanding anything; you're just missing a couple of pieces of the puzzle.

Foreign keys are implemented internally using row-level locking; starting from Postgres 8.1 and up to 9.2, whenever you update the referencing table (apples in this case), a query is fired that does SELECT FOR SHARE on the referenced table (trees). So that SELECT FOR UPDATE in the first transaction blocks the SELECT FOR SHARE of the referential integrity for the second transaction. This is what causes the block in the second command.

Now I hear you yell, “Wait! How come it blocks on the second command and not the first? The explanation is simple, really -- that's just because there is a simple optimization that skips the internal SELECT FOR SHARE when the key is not being modified. However, this is simplistic in that if you update a tuple a second time, this optimization will not fire because it's harder to track down the original values. Hence the blockage.

You might also be wondering why I said this is up to 9.2 --- what's with 9.3? The main difference there is that in 9.3 it uses SELECT FOR KEY SHARE, which is a new, lighter lock level; it allows for better concurrency. If you try your example in 9.3 and also change the SELECT FOR UPDATE to SELECT FOR NO KEY UPDATE (which is a lighter mode than SELECT FOR UPDATE that says you are maybe going to update the tuple, but you promise to not modify the primary key and promise not to delete it), you should see it doesn't block. (Also, you can try an UPDATE on the referenced row and if you don't modify the primary key, then it will also not block.)

This 9.3 stuff was introduced by a patch by yours truly as http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0ac5ad5134f2769ccbaefec73844f8504c4d6182 and I think it was a pretty cool hack (The commit message has some more details, if you care about that sort of stuff). But beware, do not use versions prior to 9.3.4 because that patch was so hugely complex that a few serious bugs went unnoticed and we only fixed recently.

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