行是否在SELECT ... ORDER BY ... FOR UPDATE语句中按顺序锁定?

时间:2018-08-22 17:27:19

标签: sql postgresql postgresql-9.5 database-deadlocks

这个问题可以被视为对我对Can two concurrent but identical DELETE statements cause a deadlock?的评论的后续行动。

我想知道在以下语句中行是否以my_status的顺序锁定:

SELECT 1 FROM my_table ORDER BY my_status FOR UPDATE;

https://www.postgresql.org/docs/9.5/static/sql-select.html上有一个有趣的说法:

  

在事务隔离级别SELECT上运行并使用READ COMMITTED和锁定子句的ORDER BY命令可能会无序返回行。这是因为首先应用ORDER BY。该命令对结果进行排序,但随后可能会阻止尝试获得对一个或多个行的锁定。 SELECT解除阻塞后,某些排序列值可能已被修改,从而导致这些行似乎是乱序的(尽管就原始列值而言,它们是有序的)。可以通过在子查询中放置FOR UPDATE / SHARE子句来解决此问题,例如

SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1;

我不确定是否能回答我的问题。这说明,首先应用ORDER BY,并且需要将FOR UPDATE放在子查询中,以解决如果order列的值实际输出顺序可能不同的副作用在此期间已更改。换句话说,将FOR UPDATE放在子查询中可确保在订购之前进行锁定。

但这并不能真正告诉我们行是否实际上按照ORDER BY子句确定的顺序锁定了?

1 个答案:

答案 0 :(得分:2)

ORDER BY子句的顺序锁定行,就像扫描表时一样

执行查询并对行进行排序,然后PostgreSQL依次锁定行。本质上,ORDER BY发生在FOR UPDATE之前。

现在,由于并发事务持有的锁,可能会锁定行阻塞。如果发生这种情况,并且我们处于READ COMMITTED隔离级别,则PostgreSQL 等待,直到它获得锁并然后获取该行的当前版本,该行它会锁定。

如果并发事务修改了定义顺序的列,则最终结果将不符合ORDER BY定义的顺序。