Ищем подходящую комбинацию табличных подсказок - PullRequest
0 голосов
/ 22 ноября 2018

Мне нужно выполнить некоторые транзакции 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, но был бы признателен за экспертное мнение.

1 Ответ

0 голосов
/ 22 ноября 2018

Это должно предотвратить дублирование.Добавлен дополнительный столбец, чтобы проиллюстрировать, как использовать больше столбцов:

DECLARE @val INT
INSERT MyTable(MyValue, val2)
SELECT coalesce(max(MyValue),0) + 1, @val
FROM mytable

Чтобы убедиться, создайте также уникальные ограничения:

ALTER TABLE MyTable   
ADD CONSTRAINT UC_MyValue UNIQUE (MyValue);   
...