Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 lock  [new]
no56892
Member

Откуда:
Сообщений: 591
Никак не могу понять как в скл сервере работают блокировки. Допустим есть таблица T с 3 полями INT A, B, C. Без индексов.
И там 4 записи, у двух например в поле А значение 1. Уровень транзакций - READ COMMITTED.
Что происходит при выполнении запроса:
UPDATE T set B = 1 WHERE A = 1

?
Допустим каждая запись это ROW. Начинается TABLE SCAN.
1.Попытка установить блокировку U на ROW1. Если успешно идем дальше, нет - ждем.
2.Аналогично для ROW2
3.Аналогично для ROW3
4.Аналогично для ROW4

То есть в какой то момент на всех записях стоит U? Либо на каждом шаге проверяется условие и только тогда ставится U?
В какой момент она заменятся на Х? перед самым коммитом?

Собственно если параллельно выполнить запрос
SELECT * FROM T WHERE C = 10

То при условии что записи будут блокироваться в разном порядке возможен дедлок? Селект наткнулся на ROW на котором апдейт уже оставил U, в то же время апдейт не сможет сделать из U->X тк на записи стоит S от селекта?
8 ноя 19, 21:58    [22012617]     Ответить | Цитировать Сообщить модератору
 Re: lock  [new]
invm
Member

Откуда: Москва
Сообщений: 8845
no56892
Либо на каждом шаге проверяется условие и только тогда ставится U?
В какой момент она заменятся на Х? перед самым коммитом?
Все не так.

В вашем конкретном случае сканирования кучи, упрощенно:
- на строку ставится U
- если строка удовлетворяет предикату, U конвертируется в X и значение столбца обновляется, иначе U снимается.

И так для каждой сканируемой строки.
8 ноя 19, 22:31    [22012625]     Ответить | Цитировать Сообщить модератору
 Re: lock  [new]
Gerros
Member

Откуда: Харьков
Сообщений: 480
no56892
Собственно если параллельно выполнить запрос
SELECT * FROM T WHERE C = 10
То при условии что записи будут блокироваться в разном порядке возможен дедлок? Селект наткнулся на ROW на котором апдейт уже оставил U, в то же время апдейт не сможет сделать из U->X т.к. на записи стоит S от селекта?
Deadlock не случится. Update будет ждать, select прочитает запись и снимет S-lock (если в read committed), update сменит U-lock на X-lock, обновит строку, снимет блокировку и пойдёт дальше. Теперь обратный вариант: select хочет поставить S-lock на следующую строку, но на ней X-lock от update, поэтому select ждёт снятия. Когда update закончит, он снимет X-lock и select продолжит работу. Это упрощённо, без IS и IX блокировок.
Если select в serializable, а update по-прежнему в read committed, deadlock тоже не случается: select не снимает наложенный S-lock до завершения транзакции, но update снимает X-lock после каждого изменения. Что бы ни делал update, select рано или поздно прочитает всё что ему нужно и снимет свой S-lock, после чего update сможет продолжить и завершить свою работу.

Deadlock-и возникают, когда оба конкурирующих процесса в repeatable read и выше.
9 ноя 19, 01:16    [22012647]     Ответить | Цитировать Сообщить модератору
 Re: lock  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1056
no56892,

добавлю к ответившим:
что бы лучше понять механизм блокировок запустите на тестовых вариациях запросов трассироку/xevent на события lock:aquired/lock:released.
тогда вы будете видеть наглядную картину что происходит в момент наложения/снятия блокировок
9 ноя 19, 03:35    [22012654]     Ответить | Цитировать Сообщить модератору
 Re: lock  [new]
invm
Member

Откуда: Москва
Сообщений: 8845
no56892,

Дополню.

Дедлочность select- update (в смысле читатель - писатель) зависит от множества факторов: наличия индексов, TIL читателя, хинтов в запросе, порядка просмотра записей.
Утверждение
Gerros
Deadlock-и возникают, когда оба конкурирующих процесса в repeatable read и выше.
неверное.
Дедлочить может и когда читатель на read committed. Для писателя же TIL практически не важен.
В вашем конкретном случае (таблица-куча без индексов) дедлока не будет, потому что читатель не накладывает более одной блокировки при обработке строки и не удерживает ее до конца транзакции.

Изучать процессы блокирования с помощью Extended Events, ИМХО, слишком накладно.
Гораздо проще в SSMS вот так (само-собой в тестовом окружении):
use tempdb;
go

create table dbo.t (id int, a int);
insert into dbo.t values (1, 0), (1, 2), (2, 3);
create index IX_t__id on dbo.t (id);
go

/*Какие ресурсы будут блокироваться*/
select object_id('dbo.t');
select %%lockres%%, * from dbo.t;
select %%lockres%%, * from dbo.t with (index = IX_t__id);
go

print '------------------------------------------ Table Scan -------------------------------------------------------';
begin tran;
dbcc traceon(3604, 1200, -1) with no_infomsgs;
update t set a = 100 from dbo.t t with (index = 0) where id = 1 and a > 0;
dbcc traceoff(3604, 1200, -1) with no_infomsgs;
rollback;
print '-------------------------------------------------------------------------------------------------------------';

print '------------------------------------------ Index Seek -------------------------------------------------------';
begin tran;
dbcc traceon(3604, 1200, -1) with no_infomsgs;;
update t set a = 100 from dbo.t t with (index = IX_t__id) where id = 1 and a > 0;
dbcc traceoff(3604, 1200, -1) with no_infomsgs;
rollback;
print '-------------------------------------------------------------------------------------------------------------';
go

drop table dbo.t;
go

Результаты будут на вкладке messages
9 ноя 19, 14:21    [22012752]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить