Укрупнення блокування - це процес перетворення багатьох дрібногранульований блокувань в менше число крупногранулірованних блокувань при ймовірне збільшення конкуренції паралелізму.
У міру того, як компонент SQL Server Database Engine отримує низькорівневі блокування, він встановлює блокування намірів на об'єкти, що містять об'єкти нижчого рівня.
При блокуванні рядків або діапазонів ключів індексу компонент Database Engine поміщає блокування намірів на сторінки, що містять ці рядки або ключі.
При блокуванні сторінок компонент Database Engine поміщає блокування на об'єкти більш високого рівня, що містять ці сторінки. Крім блокування намірів об'єкта сторінкові блокування створюються для наступних об'єктів.
Некластерізованний індекси кінцевого рівня
Сторінки даних кластеризованих індексів
Сторінки даних купи
Компонент Database Engine може для однієї і тієї ж інструкції встановлювати блокування як на рядки, так і на сторінки, щоб звести до мінімуму кількість блокувань і виключити необхідність укрупнення цього блокування. Наприклад, компонент Database Engine може встановлювати блокування сторінок в некластерізованний індексі (якщо вибрано достатнє число послідовних ключів в вузлі індексу, щоб відповідати умовам запиту) і блокування рядків в сторінках даних.
Щоб укрупнити блокування, компонент Database Engine намагається змінити блокування з наміром в таблиці на відповідну повне блокування, наприклад змінити блокування з наміром монопольного доступу (IX) на монопольну (X) або блокування з наміром поєднувати доступу (IS) на суміщати (S). Якщо спроба укрупнення блокування закінчилася успішно, і отримана повне блокування таблиці, то звільняються всі блокування купи, збалансованого дерева, сторінок (PAGE), а також блокування на рівні рядків (RID), які утримувалися транзакцією на купу або індекс. Якщо не вдалося отримати повне блокування, в цей момент укрупнення блокування не відбувається і компонент Database Engine продовжить отримувати блокування рядків, ключів або сторінок.
Блокування на рівні HoBT зазвичай підвищують паралелізм, але створюють потенційний ризик взаимоблокировки в тому випадку, коли транзакції блокують різні секції і намагаються поширити монопольну блокування на інші секції. У рідкісних випадках гранулярность блокування TABLE може виявитися більш вдалим рішенням.
Якщо спроба укрупнення блокування закінчується невдачею через конфліктуючих блокувань, утримуваних паралельними транзакціями, компонент Database Engine повторює спробу для кожних додаткових 1 250 блокувань, отриманих транзакцією.
Кожна подія укрупнення відбувається, перш за все, на рівні однієї інструкції компонента Transact-SQL. На початку події компонент Database Engine намагається укрупнити всі блокування, що належать поточної транзакції, у всіх таблицях, на які посилається активна інструкція, за умови, що вона задовольняє вимогам порога підвищення. Якщо подія укрупнення починається до того, як інструкція отримала доступ до таблиці, спроби укрупнення блокувань для цієї таблиці не розпочинаються. Якщо укрупнення блокування пройшло успішно, всі блокування, отримані транзакцією в попередньої інструкції і все ще утримуються в момент початку події, підвищуються, якщо на таблицю посилається поточна транзакція і таблиця включена в подія підвищення.
Припустимо, що сеанс виконує наступні операції:
Оновлює таблицю TableA. Цим формуються монопольні блокування рядків в таблиці TableA. які утримуються до завершення транзакції.
Оновлює таблицю TableB. Цим формуються монопольні блокування рядків в таблиці TableB. які утримуються до завершення транзакції.
Виконує інструкцію SELECT, що сполучає таблиці TableA і TableC. План виконання запиту передбачає витяг рядків з таблиці TableA до вилучення рядків з таблиці TableC.
Інструкція SELECT викликає укрупнення блокування при добуванні рядків з таблиці TableA до того, як вона отримує доступ до таблиці TableC.
Якщо укрупнення блокування пройшло успішно, укрупнюються тільки блокування, утримувані сеансом на таблицю TableA. Вони включають як поєднувані блокування інструкції SELECT, так і монопольні блокування попередньої інструкції UPDATE. У той час як для визначення необхідності укрупнення враховуються тільки блокування, які сеанс отримав для інструкції SELECT в TableA. після успішного укрупнення блокувань все блокування, утримувані сеансом в таблиці TableA. укрупнюються до монопольної блокування таблиці, а всі інші блокування з більш низькою гранулярністю, включаючи блокування з наміром в TableA. звільняються.
Спроби укрупнити блокування в таблиці TableB не розпочинаються, оскільки в інструкції SELECT не було активних посилань на таблицю TableB. Точно так само не робилися спроби укрупнити блокування в таблиці TableC. тому що до моменту укрупнення до неї не було отримано доступ.
Укрупнення блокування включається в тому випадку, якщо не виключене для таблиці за допомогою параметра ALTER TABLE SET LOCK_ESCALATION, і якщо виконується одна з наступних умов.
Одна інструкція Transact-SQL отримує більше 5 000 блокувань в одній несекціонірованной таблиці або індексі.
Одна інструкція Transact-SQL отримує більше 5 000 блокувань в одній секції секціонірованной таблиці, а параметр ALTER TABLE SET LOCK_ESCALATION встановлений в значення AUTO.
Число блокувань в екземплярі компонента Database Engine перевищує обсяг пам'яті або задані порогові значення.
Якщо блокування не можуть бути укрупнені через конфлікти блокувань, компонент Database Engine періодично ініціює укрупнення блокування при отриманні кожних 1 250 нових блокувань.
Пороги укрупнення для інструкції Transact-SQL
Укрупнення блокувань виконується тільки для таблиць, доступ до яких був отриманий після запуску підвищення. Припустимо, що інструкція SELECT є з'єднанням, яка отримує доступ до трьох таблиць в наступній послідовності: TableA. TableB і TableC. Ця інструкція отримує 3 000 блокувань рядків в кластерізованний індексі таблиці TableA і принаймні 5 000 блокувань рядків в кластерізованний індексі таблиці TableB. але ще не отримала доступ до таблиці TableC. Якщо компонент Database Engine виявляє, що інструкція отримала, по крайней мере, 5 000 блокувань рядків в таблиці TableB. він намагається укрупнити всі блокування, утримувані поточної транзакцією в таблиці TableB. Цей компонент також намагається укрупнити всі блокування, утримувані поточної транзакцією в таблиці TableA. але, оскільки число блокувань в TableA менше 5 000, спроба закінчиться невдачею. У таблиці TableC такі спроби не робляться, оскільки до неї не було отримано доступ до часу укрупнення блокувань.
Поріг укрупнення для екземпляра компонента Database Engine
Кожен раз, коли кількість блокувань перевищує поріг пам'яті для укрупнення блокування, компонент Database Engine ініціює укрупнення блокування. Поріг пам'яті залежить від параметра конфігурації locks:
Якщо параметр locks має значення за замовчуванням 0, поріг укрупнення блокувань досягається, якщо пам'ять, яка використовується об'єктами блокування, становить 24% від пам'яті компонента Database Engine, виключаючи пам'ять AWE. Структура даних, що представляє блокування, має довжину приблизно в 100 байт. Цей поріг динамічний, оскільки компонент Database Engine динамічно отримує і звільняє пам'ять з метою компенсації мінливої робочого навантаження.
Якщо параметр locks має значення, відмінне від 0, поріг укрупнення блокувань становить 40 відсотків (або менше, якщо пам'яті мало) від значення параметра locks.
Компонент Database Engine може вибирати для укрупнення будь-яку активну інструкцію з сеансу, і для 1 250 нових блокувань він вибирає інструкції для підвищення, якщо використовувана блокуваннями пам'ять в екземплярі перевищує поріг підвищення.