Ответ 1
В PostgreSQL строки будут заблокированы по мере их обновления - на самом деле способ, которым это фактически работает, состоит в том, что каждый кортеж (версия строки) имеет системное поле с именем xmin
, чтобы указать, какая транзакция сделала этот кортеж текущей (путем вставки или обновления) и системного поля, называемого xmax
, чтобы указать, какая транзакция истекла, что кортеж (путем обновления или удаления). Когда вы получаете доступ к данным, он проверяет каждый кортеж, чтобы определить, является ли он видимым для вашей транзакции, путем проверки вашего активного "моментального снимка" на эти значения.
Если вы выполняете UPDATE и кортеж, который соответствует вашим условиям поиска, имеет xmin, который сделает его видимым для моментального снимка и xmax активной транзакции, он блокирует, ожидая завершения этой транзакции. Если транзакция, которая сначала обновила кортеж, откат, ваша транзакция просыпается и обрабатывает строку; если первая транзакция завершается, транзакция просыпается и принимает действие в зависимости от текущего уровня изоляции транзакции.
Очевидно, что тупик является результатом этого события в разных строках. В ОЗУ нет блокировки на уровне строк, которые могут быть получены для всех строк одновременно, но если строки обновляются в том же порядке, вы не можете иметь циклическую блокировку. К сожалению, предложенный синтаксис IN(1, 2)
не гарантирует этого. В разных сеансах могут быть разные факторы калькуляции, фоновая "аналитическая" задача может изменять статистику для таблицы между генерацией одного плана и другой, или может использоваться seqscan и подвержена влиянию оптимизации PostgreSQL, которая вызывает новый seqscan присоединиться к уже существующему и "обойти" для уменьшения ввода/вывода диска.
Если вы делаете обновления по одному в том же порядке, в коде приложения или с помощью курсора, тогда у вас будет только простая блокировка, а не взаимоблокировки. В целом, однако, реляционные базы данных подвержены ошибкам с сериализацией, и лучше всего получить к ним доступ через фреймворк, который распознает их на основе SQLSTATE и автоматически повторит всю транзакцию с самого начала. В PostgreSQL при сбое в сериализации всегда будет SQLSTATE из 40001 или 40P01.
http://www.postgresql.org/docs/current/interactive/mvcc-intro.html