SQL Server 2012 не использует специально созданный некластеризованный индекс в операторе обновления и вызывает взаимоблокировки - PullRequest
0 голосов
/ 06 августа 2020

Моя Java программа выполняет следующие параметризованные операторы (имя таблицы и имя столбца изменены) одновременно.

insert into t_test (a,b,c) values (@param1, @param2, @param3)
update t_test set a=@param1 where id=@param2
update t_test set a=@param1 where a=@param2 and b=@param3 and c=@param4

Структура таблицы

CREATE TABLE t_test (
    [id]            [bigint] IDENTITY(1,1) NOT NULL PRIMARY KEY,
    [a]             [int] NULL,
    [b]             [int] NULL,
    [c]             [int] NULL
);

И индекс создается специально для этого запроса:

CREATE NONCLUSTERED INDEX [i_test] ON [t_test] (a,b,c);

Из планов запросов я обнаружил, что, когда размер таблицы был ниже ~ 3000 строк, база данных выбирала строки для обновления с помощью сканирования кластерного индекса; в то время как после того, как размер таблицы вырос до более чем ~ 3000 строк, база данных начала использовать i_test.

Проблема в том, что если база данных использует сканирование кластерного индекса, она попытается получить U-блокировку на каждая строка t_test, что вызывает взаимоблокировки при одновременном выполнении.

Фактические запросы выглядят примерно так:

Транзакция A:

insert into t_test (a,b,c) values (1, 1, 0)
-- say the id inserted is 1
update t_test set a=1 where id=1
update t_test set a=1 where a=1 and b=2 and c=0 --Deadlock

Транзакция B:

insert into t_test (a,b,c) values (1, 2, 0)
-- say the id inserted is 2
update t_test set a=1 where id=2
update t_test set a=1 where a=1 and b=2 and c=0  --Deadlock
* *
...