Почему UPDATE блокирует SELECT для несвязанных строк? - PullRequest
1 голос

Имея таблицу, определенную скриптом [1], я выполняю скрипты в 2-х окнах SSMS

--1) first in first SSMS window
set transaction isolation level READ UNCOMMITTED;
begin transaction;
update aaa set Name ='bbb' 
    where id=1;
-- results in "(1 row(s) affected)"
--rollback

и после 1)

--2)after launching 1)
select * from aaa --deleted comments
where id<>1
--is blocked

Независимо от уровня изоляции транзакции в1) окно ВЫБОР в 2) заблокировано.
Почему?

Влияет ли уровень изоляции для UPDATE на операторы других транзакций?

Наивысшим уровнем изоляции является значение READ COMMITTED по умолчанию в 2).
Блокировки диапазона не приписаны, SELECT должен был пострадать из-за проблем COMMITTED READS (NREREPEATABLE READ) и PHANTOM READS (Repeatable Reads) [2]
Как заставить его страдать?

Как сделать UPDATE без блокировки SELECT?

[1]

CREATE TABLE aaa
(
    Id int IDENTITY(1,1) NOT NULL,
    Name  varchar(13) NOT NULL
)


insert into  aaa(Name) 
   select '111' union all 
   select '222' union all 
   select '333' union all 
   select '444' union all 
   select '555' union all 
   select '666' union all 
   select '777' union all 
   select '888'  

[2]
Копировать и вставить или добавить трейлинг) после нажатия
http://en.wikipedia.org/wiki/Isolation_(database_systems)

Обновление:
SELECT WITH (NOLOCK) не блокируется ...

Update2:
или с, что то же самое, READ UNCOMMITTED

Обратите внимание, что UPDATE отличается от строки SELECT.
Даже если это то же самое, это поведение противоречит описанию уровней изоляции [2]

Суть в том, что:

  • предположим, я не могу знать, кто еще собирается ВЫБРАТЬиз той же таблицы (UPDATE-d), но не связанной для обновления строк
  • для понимания уровней изоляции [2]

SQL Server 2008 R2 Dev

Ответы [ 2 ]

6 голосов
/ 25 октября 2010

Я полагаю, что это потому, что у вас нет первичного ключа, что, по-моему, приводит к усилению блокировок и, следовательно, к блокировке SELECT. Если вы добавите PRIMARY KEY в столбец ID, вы заметите, что если вы попытаетесь снова, SELECT вернет остальные 3 строки - подсказка WITH (NOLOCK) не требуется.

2 голосов

Повторные испытания после

--3)
create index IX_aaa_ID on aaa(id)

ВЫБРАТЬ 2) все еще заблокирован

--4)
drop index IX_aaa_ID on aaa
create unique index IX_aaa_ID on aaa(id)
--or adding primary key constraint   

ВЫБРАТЬ 2) НЕ заблокирован

Если изменить 2) как

--2b)
select * from aaa 
    where id=3 
    --or as
    --WHERE id=2 

показывает, что 2b) не блокируется даже при отсутствии какого-либо индекса или PK.

Хотя, 2b), без каких-либо индексов, блокируется после изменения 1) UPDATE для запуска под сериализуемым но не в режиме повторного чтения или ниже

--1c)  
set transaction isolation level serializable;
--set transaction isolation level REPEATABLE READ;

begin transaction;
update aaa set Name ='bbb' 
    where id=1;
--rollback

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

Обновление:
Что ж, во всех случаях блокировка SELECT ожидает получения LCK_M_IS
Хорошая причина понять эту кухню

Update2:
Ну, это не блокировка UPDATE, которая эскалируется в таблице, это блокировки SELECT (общие) (когда SELECT пытается прочитать несколько строк), которые эскалируются в блокировку таблицы и не могут быть предоставлены, потому что таблица уже исключена (UPDATE). ) замок.

И наличие или отсутствие индекса не было связано с моим основным вопросом

Я перенес обсуждение этой темы на мое предложение «Намеренные блокировки строк не следует переводить в блокировку таблицы, если таблица уже содержит монопольную блокировку»

...