Збентежений щодо 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]

З вікна 1 SSMS:

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)проти (HOLDLOCK)самостійно?


Подальше пояснення того, що я намагаюся досягти:

Я хотів би виділити рядки з таблиці та запобігти змінам даних у цій таблиці під час її обробки. Я не змінюю ці дані і хочу дозволити читання.

Ця відповідь чітко говорить, що (UPDLOCK, HOLDLOCK)блокуватиме читання (не те, що я хочу). Коментарі до цієї відповіді означають, що саме це HOLDLOCKзаважає читати. Щоб спробувати краще зрозуміти наслідки підказки таблиці та зрозуміти, чи UPDLOCKбуде один робити те, що я хотів, я провів вищезазначений експеримент і отримав результати, які суперечать цим відповідям.

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

Відповіді:


102

Чому вибирається блок UPDLOCK? Блокування Сумісність Матричні ясно показує , Nдля S / U і U / S твердження, як і в немає конфлікту .

Щодо підказки HOLDLOCK, в документації зазначено:

HOLDLOCK: еквівалентно СЕРІАЛІЗАЦІЇ. Для отримання додаткової інформації див. СЕРІАЛІЗАЦІЮ далі в цій темі.

...

SERIALIZABLE: ... Сканування виконується з тією ж семантикою, що і транзакція, що виконується на рівні ізоляції SERIALIZABLE ...

і тема Рівень ізоляції транзакцій пояснює, що означає СЕРІАЛІЗОВАНЕ:

Жодні інші транзакції не можуть змінювати дані, прочитані поточною транзакцією, доки поточна транзакція не буде завершена.

Інші транзакції не можуть вставити нові рядки зі значеннями ключів, які потраплять у діапазон ключів, прочитаних будь-якими операторами поточної транзакції, поки поточна транзакція не завершиться.

Тому поведінка, яку ви бачите, чудово пояснюється документацією до продукту:

  • UPDLOCK не блокує одночасний SELECT або INSERT, але блокує будь-яке UPDATE або DELETE рядків, вибраних T1
  • HOLDLOCK означає СЕРІЗАЦІЙНИЙ і, отже, дозволяє ВИБРАТИ, але блокує ОНОВЛЕННЯ та ВИДАЛЕННЯ рядків, виділених T1, а також будь-який INSERT у діапазоні, вибраному T1 (це вся таблиця, отже, будь-яка вставка).
  • (UPDLOCK, HOLDLOCK): ваш експеримент не показує, що б блокувало на додаток до наведеного вище випадку, а саме іншої транзакції з UPDLOCK в T2 :
    SELECT * FROM dbo.Test WITH (UPDLOCK) WHERE ...
  • TABLOCKX не потребує пояснень

Справжнє питання полягає в тому, чого ви намагаєтесь досягти ? Гра з натяками на блокування без абсолютно повного 110% розуміння семантики блокування вимагає неприємностей ...

Після редагування OP:

Я хотів би виділити рядки з таблиці та запобігти змінам даних у цій таблиці під час її обробки.

Вам слід використовувати один із вищих рівнів ізоляції транзакцій. ПОВТОРНЕ ЧИТАННЯ запобігає зміні прочитаних даних. SERIALIZABLE запобіжить зчитує дані від зміни і нові дані вставляються. Використання рівнів ізоляції транзакцій - правильний підхід на відміну від використання підказок. Кендра Літтл має приємний плакат, що пояснює рівні ізоляції .


+1, і дякую за докладну відповідь. Я оновлю своє запитання, щоб додати деталі моєї мети.
Джефф Огата,

1
@Remus Rusanu, не могли б Ви пояснити, чому правильний підхід використовує рівні ізоляції на відміну від використання підказок? У мене є процедура, коли мені потрібно лише заблокувати дві таблиці від модифікації, і я використовую TABLOCK, HOLDLOCK, чи справді я повинен перейти на рівень ізоляції та заблокувати таблиці alls у своїй транзакції?
Стів

Я міг би отримати пояснення щодо TABLOCKX :)
niico

Примітка: Посилання на запис у блозі для Кендри Літтл повертає 404. Я не можу знайти жодного запису від 2 лютого 2011 року, як випливає із посилання.
Bacon Bits

22

UPDLOCK використовується, коли потрібно заблокувати рядок або рядки під час вибору оператора для майбутнього виписки оновлення. Майбутнє оновлення може бути найближчим твердженням транзакції.

Інші сеанси все ще можуть бачити дані. Вони просто не можуть отримати замки, несумісні з UPDLOCK та / або HOLDLOCK.

Ви використовуєте UPDLOCK, коли хочете, щоб інші сеанси не змінювали заблоковані рядки. Це обмежує їх можливість оновлювати або видаляти заблоковані рядки.

Ви використовуєте HOLDLOCK, коли хочете, щоб інші сеанси не змінювали будь-які дані, які ви переглядаєте. Це обмежує їх можливість вставляти, оновлювати чи видаляти заблоковані рядки. Це дозволяє повторно запустити запит і побачити ті самі результати.


1
Дякую, але я не думаю, що ви дійсно відповіли на моє запитання: чи були відповіді на ці запитання неправильними, зазначаючи, що (UPDLOCK,HOLDLOCK)блок читається, і чи є причина використовувати (UPDLOCK,HOLDLOCK)замість просто (HOLDLOCK)?
Джефф Огата,

Моє друге твердження відповідає на ваше запитання, вони помиляються. Інші сеанси все ще можуть читати дані.
Скотт Бранс,

Updlock, Holdlock - це не те саме, що holdlock. Updlock, holdlock блокує рядки для оновлення та серіалізує вашу транзакцію. Самоблокування просто серіалізує вашу транзакцію. Він не блокує вибрані рядки для подальшого доступу.
Скотт Бранс,

"UPDLOCK використовується, коли ви хочете заблокувати рядок або рядки під час вибору оператора для майбутнього оператора оновлення." Мені це подобається, оскільки XLOCK може колись не працювати
Yiping
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.