Уровни изоляции транзакций и подзапросы

если у нас есть UPDATE с вложенным SELECT, может ли подзапрос выполняться одновременно или нет в изоляции READ COMMITTED?

Другими словами, присутствует ли состояние гонки в следующем:

update list set [state] = 'active' 
where
    id = (select top 1 id from list where [state] = 'ready' order by id)

Другими словами, если множество соединений одновременно выполняют этот SQL, можем ли мы гарантировать, что одна строка действительно обновляется при каждом вызове (пока существуют строки в состоянии «готово»)?


person The Dag    schedule 09.05.2014    source источник
comment
Включение нескольких операций в один оператор никак не помогает с параллелизмом. Операторы не предоставляют никаких гарантий, связанных с параллелизмом.   -  person usr    schedule 09.05.2014
comment
Это неправильно. Общие блокировки берутся и снимаются для одного оператора SELECT за раз в READ COMMITTED. Но я не уверен, какие блокировки порядка взяты для примера. Я также вполне счастлив поставить begin tran и зафиксировать его, хотя я совершенно уверен, что это не имеет значения, поскольку транзакция никогда не может быть меньше, чем один оператор.   -  person The Dag    schedule 09.05.2014
comment
Нет. READ COMMITTED освобождает блокировки как можно скорее, часто после каждой строки. Для страниц, на которых нет незафиксированных данных, он вообще не блокируется. Это малоизвестная оптимизация.; Я также очень рад положить начало трансу и зафиксировать его, это еще одно заблуждение, что это что-то изменит. В режиме автоматической фиксации операторы по-прежнему выполняются в рамках неявной транзакции. Вы правы в этом отношении.   -  person usr    schedule 09.05.2014
comment
Интересно, почему документ MSDN так недвусмысленно заявляет: поскольку общие блокировки [в REPEATABLE READ] удерживаются до конца транзакции, а не освобождаются В КОНЦЕ КАЖДОГО УТВЕРЖДЕНИЯ [выделено мной], параллелизм ниже, чем изоляция READ COMMITTED по умолчанию уровень.   -  person The Dag    schedule 09.05.2014
comment
Это утверждение о REPEATABLE READ, которое навсегда использует S-блокировки для обеспечения стабильности данных. READ COMMITTED не гарантирует стабильность данных. Это почти ничего не гарантирует.   -  person usr    schedule 09.05.2014
comment
sqlperformance.com/2014/04/t- sql-queries/ Отличная серия на этом сайте о блокировках.   -  person usr    schedule 09.05.2014
comment
Да, конечно, это написано в разделе ПОВТОРЯЕМОЕ ЧТЕНИЕ - поэтому я ДОБАВИЛ это в цитату, в квадратных скобках и все такое. Дело в том, что он явно говорит, что разделяемые блокировки снимаются в конце каждого оператора READ COMMITTED. Я вижу, что ваши связанные ресурсы утверждают иначе.   -  person The Dag    schedule 09.05.2014
comment
О, теперь я понимаю, что вы имеете в виду. Попробуйте следующее: просканируйте таблицу размером 1 ТБ в RC и используйте sp_locks на полпути, чтобы увидеть, что существует лишь небольшое количество блокировок. Нет S-блокировки на уровне таблицы. Или прочитайте серию, на которую я дал ссылку. Это очень хорошо.; Да, заявление MSDN вводит в заблуждение. Ошибка документации.   -  person usr    schedule 09.05.2014
comment
Вы также можете увидеть каждую блокировку, взятую с помощью SQL Profiler.   -  person usr    schedule 09.05.2014
comment
давайте продолжим это обсуждение в чате   -  person The Dag    schedule 09.05.2014


Ответы (1)


Ответ да, существует состояние гонки, и две транзакции могут выполнять подзапрос одновременно, что приводит к тому, что одна и та же строка впоследствии обновляется дважды.

Это можно исправить, переписав обновление как

update TEMP 
set [state] = 'active' 
from 
    (select top 1 * from list where [state] = 'ready' order by id) TEMP

Я, честно говоря, не знаю, почему это должно быть по-другому, но это так. SQL Server теперь будет блокировать обновление («намерение обновить») при выполнении подзапроса, предотвращая выбор одной и той же строки параллельными транзакциями.

person The Dag    schedule 12.05.2014