Смущенный по поводу UPDLOCK, HOLDLOCK - PullRequest
76 голосов
/ 21 октября 2011

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

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

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

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) против (HOLDLOCK) в одиночку?


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

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

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

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

Ответы [ 2 ]

92 голосов
/ 21 октября 2011

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

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

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

...

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

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

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

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

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

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

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

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

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

Следует использовать один из более высоких уровней изоляции транзакции.REPEATABLE READ предотвратит изменение прочитанных вами данных.SERIALIZABLE предотвратит изменение прочитанных вами данных и новые данные будут вставлены.Использование уровней изоляции транзакций является правильным подходом, в отличие от использования подсказок запросов.У Кендры Литтл красивый плакат с описанием уровней изоляции .

20 голосов
/ 21 октября 2011

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

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

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

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

...