Смутно о UPDLOCK, HOLDLOCK

При исследовании использования Table Hints я столкнулся с этими двумя вопросами:

Ответы на оба вопроса говорят, что при использовании (UPDLOCK, HOLDLOCK) другие процессы не смогут читать данные в этой таблице, но я этого не видел. Чтобы проверить, я создал таблицу и запустил два окна SSMS. В первом окне я выполнил транзакцию, выбранную из таблицы, используя различные табличные подсказки. Пока транзакция выполнялась, из второго окна я запускал различные инструкции, чтобы увидеть, что будет заблокировано.

Таблица тестов:

CREATE TABLE [dbo].[Test](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [Value] [nvarchar](50) NULL,
 CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

Из окна SSMS 1:

BEGIN TRANSACTION

SELECT * FROM dbo.Test WITH (UPDLOCK, HOLDLOCK)
WAITFOR DELAY '00:00:10'

COMMIT TRANSACTION

Из окна SSMS 2 (выполняется одно из следующих действий):

SELECT * FROM dbo.Test
INSERT dbo.Test(Value) VALUES ('bar')
UPDATE dbo.Test SET Value = 'baz' WHERE Value = 'bar'
DELETE dbo.Test WHERE Value= 'baz'

Влияние различных табличных подсказок на операторы, выполняемые в окне 2:

           (UPDLOCK)       (HOLDLOCK)    (UPDLOCK, HOLDLOCK)    (TABLOCKX)
---------------------------------------------------------------------------
SELECT    not blocked      not blocked       not blocked         blocked
INSERT    not blocked        blocked           blocked           blocked
UPDATE      blocked          blocked           blocked           blocked
DELETE      blocked          blocked           blocked           blocked

Я неправильно понял ответы на эти вопросы или допустил ошибку при тестировании? Если нет, зачем использовать (UPDLOCK, HOLDLOCK) vs. (HOLDLOCK) самостоятельно?


Дальнейшее объяснение того, что я пытаюсь выполнить:

Я хотел бы выбрать строки из таблицы и предотвратить изменение данных в этой таблице во время обработки. Я не изменяю эти данные и хотел бы разрешить чтение.

В этом ответе четко сказано, что (UPDLOCK, HOLDLOCK) будет блокировать чтение (не то, что я хочу). Комментарии этого ответа подразумевают, что это HOLDLOCK предотвращает чтение. Чтобы лучше понять эффекты табличных подсказок и посмотреть, будет ли только UPDLOCK делать то, что я хотел, я сделал вышеупомянутый эксперимент и получил результаты, которые противоречат этим ответам.

В настоящее время я считаю, что (HOLDLOCK) - это то, что я должен использовать, но я обеспокоен тем, что, возможно, ошибся или забыл что-то, что вернется, чтобы укусить меня в будущем, следовательно, этот вопрос.

Ответ 1

Почему блок UPDLOCK выбирается? Матрица совместимости блокировки четко показывает N для утверждения S/U и U/S, как в Без конфликтов.

Что касается HOLDLOCK, то в документации указано:

HOLDLOCK: эквивалентен SERIALIZABLE. Для получения дополнительной информации см. SERIALIZABLE позже в этом разделе.

...

SERIALIZABLE:... Сканирование выполняется с той же семантикой, что и транзакция, выполняемая на уровне изоляции SERIALIZABLE...

и Уровень изоляции транзакций объясняет, что означает SERIALIZABLE:

Никакие другие транзакции не могут изменять данные, которые были прочитаны текущей транзакции до завершения текущей транзакции.

Другие транзакции не могут вставлять новые строки с ключевыми значениями, которые попадают в диапазон ключей, считываемых любыми заявлениями в текущем транзакции до завершения текущей транзакции.

Поэтому поведение, которое вы видите, прекрасно объясняется документацией продукта:

  • UPDLOCK не блокирует одновременный SELECT или INSERT, но блокирует любые UPDATE или DELETE строк, выбранных T1
  • HOLDLOCK означает SERALIZABLE и поэтому позволяет SELECTS, но блокирует UPDATE и DELETES строк, выбранных T1, а также любой INSERT в диапазоне, выбранном T1 (который представляет собой всю таблицу, поэтому любая вставка).
  • (UPDLOCK, HOLDLOCK): ваш эксперимент не показывает, что будет блокировать в дополнение к вышеприведенному случаю, а именно другую транзакцию с UPDLOCK в T2:
    SELECT * FROM dbo.Test WITH (UPDLOCK) WHERE ...
  • TABLOCKX не нуждается в пояснениях

Реальный вопрос - это то, чего вы пытаетесь достичь? Игра с подсказками с замком без абсолютного полного 110% -ного понимания смысловой семантики выпрашивает проблемы...

После редактирования OP:

Я хотел бы выбрать строки из таблицы и предотвратить данные в этом таблицу из-под изменения, пока я ее обрабатываю.

Вы должны использовать один из более высоких уровней изоляции транзакций. REPEATABLE READ предотвратит изменение данных, которые вы читаете. SERIALIZABLE предотвратит изменение данных, которые вы читаете, и новые данные от вставки. Использование уровней изоляции транзакций - правильный подход, а не использование подсказок. Kendra Little имеет приятный плакат, выходящий за уровни изоляции.

Ответ 2

UPDLOCK используется, когда вы хотите заблокировать строку или строки во время инструкции select для будущего оператора обновления. Будущее обновление может быть самым следующим оператором в транзакции.

Другие сеансы все еще могут видеть данные. Они просто не могут получить блокировки, которые несовместимы с UPDLOCK и/или HOLDLOCK.

Вы используете UPDLOCK, когда хотите, чтобы другие сеансы меняли заблокированные строки. Он ограничивает их возможность обновлять или удалять заблокированные строки.

Вы используете HOLDLOCK, если хотите, чтобы другие сеансы не меняли какие-либо данные, на которые вы смотрите. Он ограничивает их возможность вставлять, обновлять или удалять заблокированные строки. Это позволяет снова запустить запрос и увидеть те же результаты.