Автор: Craig Freedman Query Failure with Read Uncommitted
В предыдущих статьях были рассмотрены практически все уровни изоляции, за исключением Read Uncommitted или NOLOCK. Эта статья завершает серию обсуждением того, что может приключиться, если читать данные ещё не зафиксированных транзакций. О вреде NOLOCK написано уже немало. Например, вы могли об этом почитать у Любора Коллара (Lubor Kollar) из «SQL Server Development Customer Advisory Team» и в (ныне уже недоступном) блоге Тони Роджерсона (Tony Rogerson).
В дополнение к многочисленным аргументам, ниже будет продемонстрирована еще одна опасность NOLOCK. Начнём с создания двух таблиц:
create table t1 (k int, data int)
insert t1 values (0, 0)
insert t1 values (1, 1)
create table t2 (pk int primary key)
insert t2 values (0)
insert t2 values (1)
Затем в первом сеансе заблокируйте первую строку t2, используя обновление, как показано ниже:
begin tran
update t2 set pk = pk where pk = 0
Теперь во втором сеансе выполните следующий запрос:
select *
from t1 with (NOLOCK)
where exists (select * from t2 where t1.k = t2.pk)
Этот запрос использует следующий план:
|
Сканирование таблицы выбирает первую строку t1 без получения каких-либо блокировок, а затем пытается соединить эту строку с t2. Поскольку мы заблокировали первую строку в t2 и поскольку сканирование кластерного индекса t2 выполняется на уровне изоляции по умолчанию Read Committed, запрос блокируется.
Наконец, в первом сеансе удалите первую строку из t1 и зафиксируйте транзакцию:
delete t1 where k = 0
commit tran
Запрос во втором сеансе теперь можно продолжить. Однако мы только что удалили ту строку, к которой ему нужно было выполнить соединение, и чего он ждал, пока она была заблокирована. Поскольку запрос пытается получить данные из удаленной строки, он завершается ошибкой со следующим текстом:
Msg 601, Level 12, State 3, Line 1
Could not continue scan with NOLOCK due to data movement.
Как видно, сканирование с Read Uncommitted или сканирование с NOLOCK может привести не только к неверным результатам, но и даже к сбою запроса!
Комментариев нет:
Отправить комментарий