Мне нужно выполнить некоторые транзакции SQL Server (выбрать + вставить), используя блокировки, чтобы предотвратить конфликты.У меня есть следующий сценарий: у меня есть таблица, первичный ключ которой является целым числом, но не автоинкрементным (устаревший, не спрашивайте), поэтому его значение определяется следующим образом:
- выборка получаетмаксимальное значение идентификатора из таблицы
- идентификатор увеличивается на единицу
- новая запись вставляется в таблицу с использованием нового идентификатора
Все это сделанов транзакции SQL-команда выглядит следующим образом:
SELECT @maxvalue = max(MyId) FROM MyTable
IF @maxvalue > 0
SET @maxvalue = @maxvalue + 1
ELSE
SET @maxvalue = 1
INSERT INTO MyTable(MyValue, ...) VALUES(@maxvalue, ...)
В некоторых случаях это может привести к дублированию идентификаторов, и люди, которые его записали, поместили его в цикл и повторили операцию, когда произошла ошибка дублирующего ключа.,Поэтому я изменил это, удалив цикл и установив блокировки на уровне транзакции следующим образом:
SELECT @maxvalue = max(MyId) FROM MyTable WITH (HOLDLOCK, TABLOCKX)
IF @maxvalue > 0
SET @maxvalue = @maxvalue + 1
ELSE
SET @maxvalue = 1
INSERT INTO MyTable(MyValue, ...) VALUES(@maxvalue, ...)
Итак, я указал две табличных подсказки , HOLDLOCK
и TABLOCKX
.Это выглядело хорошо для некоторых баз данных, но для тех, у которых в этой таблице десятки тысяч записей, эта транзакция заняла много времени, около 10 минут.Посмотрев в SQL Server Activity Monitor, я увидел, что транзакция приостановлена, хотя спустя очень долгое время она была успешно выполнена.
Затем я изменил подсказки на (HOLDLOCK, TABLOCK)
и работает так же быстро, как и до использования подсказок.
Проблема в том, что я не уверен, что это лучшая комбинация для того, что я ищу, или что-то еще более подходящее.Я видел Смущенный по поводу UPDLOCK, HOLDLOCK и https://www.sqlteam.com/articles/introduction-to-locking-in-sql-server, но был бы признателен за экспертное мнение.