Этот вопрос можно рассматривать как продолжение моего комментария к Могут ли два параллельных, но идентичных оператора DELETE вызвать взаимоблокировку?.
Мне интересно, заблокированы ли строки в порядке возрастания my_status
в следующем утверждении:
SELECT 1 FROM my_table ORDER BY my_status FOR UPDATE;
Есть интересное замечание по поводу https://www.postgresql.org/docs/9.5/static/sql-select.html, в котором говорится:
It is possible for a
SELECT
command running at theREAD COMMITTED
transaction isolation level and usingORDER BY
and a locking clause to return rows out of order. This is becauseORDER BY
is applied first. The command sorts the result, but might then block trying to obtain a lock on one or more of the rows. Once theSELECT
unblocks, some of the ordering column values might have been modified, leading to those rows appearing to be out of order (though they are in order in terms of the original column values). This can be worked around at need by placing theFOR UPDATE
/SHARE
clause in a sub-query, for exampleSELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss ORDER BY column1;
Я не уверен, что это ответ на мой вопрос. Все это говорит о том, что сначала применяется ORDER BY
, и вам нужно поместить FOR UPDATE
в подзапрос, чтобы обойти побочный эффект, заключающийся в том, что фактический порядок вывода может отличаться, если значения столбца (столбцов) порядка были изменены за это время. Другими словами, добавление FOR UPDATE
в подзапрос гарантирует, что блокировка произойдет перед заказом.
Но на самом деле это не говорит нам, действительно ли строки заблокированы в порядке, определенном предложением ORDER BY
?
Строки блокируются в порядке, указанном в предложении ORDER BY
как это было при сканировании таблицы.
Запрос выполняется и строки упорядочиваются, затем PostgreSQL блокирует строки по порядку. По сути, ORDER BY
происходит раньше, чем FOR UPDATE
.
Теперь может случиться так, что блокировка строковых блоков из-за блокировок, удерживаемых параллельными транзакциями. Если это произойдет, и мы находимся на уровне изоляции READ COMMITTED
, PostgreSQL ждет, пока он не сможет получить блокировку и затем загружает текущую версию строки, которую он блокирует.
Если параллельная транзакция изменила столбцы, которые определяют порядок, окончательный результат не будет в порядке, определенном ORDER BY
.