Смущает UPDLOCK, HOLDLOCK

89

Изучая использование подсказок по таблицам , я столкнулся с двумя вопросами:

Ответы на оба вопроса говорят о том, что при использовании (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)alone?


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

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

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

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

Джефф Огата
источник

Ответы:

102

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

Что касается ЗАМКА подсказки документация гласит:

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 предотвратит изменение данных, которые вы читаете, и вставку новых данных. Использование уровней изоляции транзакций - это правильный подход, в отличие от использования подсказок в запросах. У Кендры Литтл есть красивый плакат, объясняющий уровни изоляции .

Ремус Русану
источник
+1, и спасибо за подробный ответ. Я обновлю свой вопрос, чтобы подробнее рассказать о моей цели.
Джефф Огата
1
@Remus Rusanu, не могли бы вы объяснить, почему правильный подход использует уровни изоляции, а не использование подсказок? У меня есть процедура, в которой мне нужно заблокировать только две таблицы от изменения, и я использую TABLOCK, HOLDLOCK, должен ли я действительно перейти на уровень изоляции и заблокировать все таблицы в моей транзакции?
Стив
Мне бы хотелось объяснить TABLOCKX :)
niico
Примечание. Ссылка на запись в блоге Кендры Литтл возвращает 404. Я не могу найти записи от 2 февраля 2011 г., как следует из ссылки.
Bacon Bits
22

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

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

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

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

Скотт Брунс
источник
1
Спасибо, но я не думаю, что вы действительно ответили на мой вопрос: были ли ответы на эти вопросы неправильными в заявлении о том, что (UPDLOCK,HOLDLOCK)блок читается, и есть ли причина использовать (UPDLOCK,HOLDLOCK)вместо просто (HOLDLOCK)?
Джефф Огата
Мое второе утверждение отвечает на ваш вопрос, они ошибочны. Другие сеансы все еще могут читать данные.
Скотт Брунс
Updlock, Holdlock - это не то же самое, что holdlock. Updlock, holdlock блокирует строки для обновления и сериализует вашу транзакцию. Holdlock сам по себе просто сериализует вашу транзакцию. Он не блокирует выбранные строки для дальнейшего доступа.
Скотт Брунс,
«UPDLOCK используется, когда вы хотите заблокировать строку или строки во время оператора выбора для будущего оператора обновления». Мне это нравится, так как XLOCK может когда-нибудь не работать
Ипин