Могут ли два параллельных, но идентичных оператора DELETE вызвать взаимоблокировку?

Предположим, что some_table имеет две строки с первичным ключом 1 и 2. Следующая последовательность операторов может вызвать тупик:

session 1: begin;
session 2: begin;
session 1: DELETE FROM my_table WHERE my_key = 1;
session 2: DELETE FROM my_table WHERE my_key = 2;
session 1: DELETE FROM my_table WHERE my_key = 2;
session 2: DELETE FROM my_table WHERE my_key = 1;

Взаимоблокировки не произошло бы, если бы оба сеанса были удалены в одном и том же порядке.

Теперь, переходя к моему вопросу, что произойдет, если оператор DELETE коснется нескольких строк? Например:

session 1: begin;
session 2: begin;
session 1: DELETE FROM my_table;
session 2: DELETE FROM my_table;

Возможно ли, что два параллельных, но идентичных оператора DELETE удалят строки в другом порядке? Можно ли принудительно применить порядок удаления, чтобы избежать тупиковой ситуации?

Мне не удалось найти эту информацию в документации, поэтому я бы сказал, что порядок удаления не гарантируется (хотя это может быть косвенно как деталь реализации). Я хотел дважды проверить здесь.

Это вызовет тупик, потому что вы не совершаете ни одной транзакции.

Ben 22.08.2018 17:34

@Ben AFAIK возможная взаимоблокировка может возникнуть во время оператора DELETE (то есть как можно раньше). Его не следует откладывать до заявления COMMIT, которого здесь действительно нет. Мой вопрос не о тривиальном тупике из-за отсутствия оператора COMMIT.

user8870331 22.08.2018 17:42

«Транзакция» действительно вызывает «сериализацию» доступа. Это гарантирует, что вся обработка завершится успешно или не удастся. Он также заблокирует ожидание использования ресурса внутри ваших транзакций, которые обращаются к тем же ресурсам. Первое, что вы делаете, это получаете и блокируете ресурсы, необходимые для завершения текущего шага транзакции. В вашем случае заблокируйте все нужные строки (выберите для обновления) или заблокируйте таблицу, получите доступ к строкам и отпустите ее. Серьезно, самый простой способ - получить доступ к ресурсам в одном и том же порядке в каждой транзакции, чтобы предотвратить «взаимоблокировки».

Ryan Vincent 22.08.2018 18:06

@RyanVincent Это вообще мой вопрос. SELECT FOR UPDATE, предшествующий DELETE, не нужен, если строки всегда удаляются в одном и том же порядке, или там, если есть способ принудительно установить порядок удаления. Если нет, то SELECT ... ORDER BY ... FOR UPDATE (SKIP LOCKED) действительно может быть полезен.

user8870331 22.08.2018 18:31

Что касается FOR UPDATE, я не уверен, работает ли это так, как мы ожидали. См. stackoverflow.com/questions/51972202/…

user8870331 22.08.2018 19:30
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
5
5
1 394
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Да, это может привести к тупиковой ситуации, потому что порядок строк в таблице не фиксирован.

Любой UPDATE может изменить порядок строк, возвращаемых последовательным сканированием таблицы, и если synchronize_seqscans имеет значение по умолчанию on, порядок может измениться, даже если таблица не изменится, если несколько последовательных сканирований выполняются одновременно (как в вашем случае).

Вы должны сначала запустить SELECT ... FOR UPDATE с предложением ORDER BY, чтобы снизить риск тупиковой ситуации, но даже в этом случае вы не можете быть абсолютно уверены, если не выполните сортировку по столбцу, который не будет обновляться одновременно (например, первичный ключ).

Спасибо, это то, что я ожидал. Что касается добавления ORDER BY, вы имели в виду что-то вроде этого: DELETE FROM my_table WHERE my_key IN (SELECT my_key FROM my_table ORDER MY my_key)? DELETE соблюдает порядок подзапроса?

user8870331 23.08.2018 10:09

Я недостаточно хорошо думал; Я отредактировал ответ. Предыдущий SELECT ... FOR UPDATE должен помочь.

Laurenz Albe 23.08.2018 10:13

Большой! Это тоже была моя мысль, поэтому я создал stackoverflow.com/questions/51972202/….

user8870331 23.08.2018 10:16

Резюме: DELETE FROM my_table WHERE my_key IN (SELECT my_key FROM my_table ORDER BY my_key FOR UPDATE (SKIP LOCKED/NOWAIT) должен давать детерминированный порядок удаления. При необходимости можно добавить SKIP LOCKED или NOWAIT.

user8870331 23.08.2018 10:17

Это должно работать, за исключением того, что NOWAIT вызовет ошибку.

Laurenz Albe 23.08.2018 10:52

Другие вопросы по теме