Моя 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
* *