Ескалація блокування - що тут відбувається?


138

Змінюючи таблицю (видаляючи стовпець) у SQL Server 2008, я натиснув кнопку Створити скрипт змін, і я помітив, що створений ним сценарій зміни опускає стовпець, каже "йти", а потім запускає додатковий оператор ALTER TABLE, який, як видається, встановлений ескалація блокування для таблиці до "ТАБЛИЦЯ". Приклад:

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

Я також повинен зазначити, що це останнє, що робить сценарій зміни. Що це робиться тут і чому він встановлює LOCK_ESCALATION на TABLE?

Відповіді:


165

" Ескалація блокування " - це те, як SQL обробляє блокування для великих оновлень. Коли SQL збирається змінити багато рядків, механізм бази даних буде більш ефективним брати менше, більших блокування (наприклад, цілу таблицю), а не блокувати багато дрібних речей (наприклад, блокування рядків).

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

У LOCK_ESCALATIONSQL 2008 є нова опція рівня таблиці , яка дозволяє контролювати ескалацію блокування. За замовчуванням "ТАБЛИЦЯ" дозволяє блокам ескалювати до рівня таблиці. DISABLE у більшості випадків запобігає ескалації блокування на всю таблицю. AUTO дозволяє блокувати таблицю, за винятком випадків, коли таблиця є розділеною, і в цьому випадку блокування виробляються лише до рівня розділу. Дивіться цю публікацію в блозі для отримання додаткової інформації.

Я підозрюю, що IDE додає цей параметр при повторному створенні таблиці, оскільки TABLE є типовим для SQL 2008. Зауважте, що LOCK_ESCALATION не підтримується в SQL 2005, тому вам потрібно буде зняти його, якщо намагаєтеся запустити сценарій на Примірник 2005 року. Крім того, оскільки TABLE за замовчуванням, ви можете безпечно видалити цей рядок під час повторного запуску сценарію.

Також зауважте, що в SQL 2005 до того, як ця настройка була присутня, усі блокування могли перейти до рівня таблиці-- іншими словами, "TABLE" був єдиним параметром у SQL 2005.


1
Дубльований пост також на форумах MSDN: social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/…
Джонатан Кехаяс

6
@dma_k - Цей параметр не відповідає, CREATE TABLEоскільки таблиця ще не існує, тому немає чого блокувати.
Джастін Грант

1
Але чому заяву LOCK_ESCALATION після початкового заяви ALTER TABLE в сценарії змін при проектуванні таблиці в SSMS? Напевно до цього часу робота вже зроблена. Чи не повинно бути цього перед тим, як змінити структуру таблиці?
Реверсивний інженер

2
@DaveBoltman - SET є частиною оператора ALTER TABLE. Це не окреме твердження. Дивіться docs.microsoft.com/en-us/sql/t-sql/statements/…
Джастін Грант

2
JustinGrant все-таки стоїть питання від @DaveBoltman. Сценарій, який створює SSMS для, скажімо, додавання нового стовпця, має два окремі ALTER TABLEзаяви. Спочатку ALTER TABLE ADD column, потім GO, потім друге ALTER TABLE SET LOCK_ESCALATION=TABLE, потім друге GO. Отже, LOCK_ESCALATIONвстановлюється після додавання стовпця. Який сенс встановлювати це після факту? Ці два ALTER TABLEвисловлювання завернуті в транзакцію, але все-таки стовпець додається перед LOCK_ESCALATIONвстановленням параметра. Думаю, я ще копаю далі і напишу ще одну відповідь.
Володимир Баранов

11

Ви можете перевірити, чи потрібно включати оператор LOCK_ESCALATION у свій сценарій, порівнявши це значення до та після запуску основної частини сценарію:

SELECT lock_escalation_desc FROM sys.tables WHERE name='yourtablename'

У моєму випадку зміна таблиці для відміни або додавання обмеження, схоже, не змінює це значення.


11

Відповідь Джастіна Гранта пояснює, що таке LOCK_ESCALATIONналаштування робить взагалі, але пропускає одну важливу деталь і не пояснює, чому SSMS генерує код, який його встановлює. Тим більше, дуже дивно виглядає те, що LOCK_ESCALATIONв сценарії встановлено останню заяву.

Я зробив кілька тестів і ось моє розуміння того, що тут відбувається.

Коротка версія

ALTER TABLEЗатвердження , яке додає, видаляє або змінює стовпець неявно приймає схему зміни (SCH-M) блокування таблиці, яка не має нічого спільного з LOCK_ESCALATIONустановкою столу. LOCK_ESCALATIONвпливає поведінка блокування під час заяв DML ( INSERT, UPDATE, DELETEі т.д.), а не під час заяв DDL ( ALTER). Замок SCH-M - це завжди блокування всього об’єкта бази даних, наведеного в цьому прикладі.

Ймовірно, звідки виходить плутанина.

SSMS додає ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)заяву до свого сценарію у всіх випадках, навіть коли це не потрібно. У випадках, коли це твердження потрібно, воно додається для збереження поточного налаштування таблиці, а не для блокування таблиці якимось певним чином під час зміни схеми таблиці, що відбувається в цьому сценарії.

Іншими словами, таблиця буде заблокована з замком SCH-M на першому ALTER TABLE ALTER COLUMNзаяві в той час як вся робота зміни схеми таблиці робиться. Останнє ALTER TABLE SET LOCK_ESCALATIONтвердження на це не впливає. Це впливає тільки на заяви майбутнього DML ( INSERT, UPDATE, DELETEі т.д.) для цієї таблиці.

На перший погляд це виглядає так, ніби SET LOCK_ESCALATION = TABLEмає щось спільне з тим, що ми змінюємо всю таблицю (ми змінюємо її схему тут), але це вводить в оману.

Довга версія

Під час зміни таблиці в деяких випадках SSMS генерує сценарій, який заново створює всю таблицю, а в деяких більш простих випадках (наприклад, додавання або випадання стовпця) сценарій не створює повторно таблицю.

Візьмемо для прикладу цю зразкову таблицю:

CREATE TABLE [dbo].[Test](
    [ID] [int] NOT NULL,
    [Col1] [nvarchar](50) NOT NULL,
    [Col2] [int] NOT 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]
GO

У кожній таблиці є LOCK_ESCALATIONналаштування, яке встановлено TABLEза замовчуванням. Давайте змінимо тут:

ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)

Тепер, якщо я спробую змінити Col1тип в дизайнері таблиць SSMS, SSMS генерує сценарій, який заново створює всю таблицю:

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
CREATE TABLE dbo.Tmp_Test
    (
    ID int NOT NULL,
    Col1 nvarchar(10) NOT NULL,
    Col2 int NOT NULL
    )  ON [PRIMARY]
GO
ALTER TABLE dbo.Tmp_Test SET (LOCK_ESCALATION = DISABLE)
GO
IF EXISTS(SELECT * FROM dbo.Test)
     EXEC('INSERT INTO dbo.Tmp_Test (ID, Col1, Col2)
        SELECT ID, CONVERT(nvarchar(10), Col1), Col2 FROM dbo.Test WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.Test
GO
EXECUTE sp_rename N'dbo.Tmp_Test', N'Test', 'OBJECT' 
GO
ALTER TABLE dbo.Test ADD CONSTRAINT
    PK_Test PRIMARY KEY CLUSTERED 
    (
    ID
    ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

GO
COMMIT

Ви можете бачити вище, що він встановлює LOCK_ESCALATIONдля новоствореної таблиці. SSMS робить це для збереження поточних налаштувань таблиці. SSMS генерує цей рядок, навіть якщо поточне значення параметра є TABLEзначенням за замовчуванням . Просто, щоб бути безпечним і явним і запобігти можливим майбутнім проблемам, якщо в майбутньому цей дефолт зміниться, я думаю. Це має сенс.

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

Якщо я спробую внести прості зміни в таблицю за допомогою дизайнера таблиць SSMS, наприклад додавання нового стовпця, то SSMS створює сценарій, який не створює повторну таблицю:

BEGIN TRANSACTION
SET QUOTED_IDENTIFIER ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
SET CONCAT_NULL_YIELDS_NULL ON
SET ANSI_NULLS ON
SET ANSI_PADDING ON
SET ANSI_WARNINGS ON
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.Test ADD
    NewCol nchar(10) NULL
GO
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
GO
COMMIT

Як бачите, він все-таки додає ALTER TABLE SET LOCK_ESCALATIONтвердження, хоча в цьому випадку він взагалі не потрібен. Перший ALTER TABLE ... ADDне змінює поточний параметр. Гадаю, розробники SSMS вирішили, що не варто намагатися визначити, у яких випадках ця ALTER TABLE SET LOCK_ESCALATIONзаява є зайвою, і генерувати її завжди, просто щоб бути безпечною. Немає жодної шкоди щоразу додавати це твердження.

Знову ж таки, параметр для загальної таблиці LOCK_ESCALATIONне має значення, тоді як схема таблиці змінюється через ALTER TABLEоператор. LOCK_ESCALATIONналаштування впливає лише на поведінку блокування в операторах DML, наприклад UPDATE.

Нарешті, цитата ALTER TABLE, підкресли мою:

Зміни, зазначені в ALTER TABLE, вводяться негайно. Якщо для змін потрібні зміни рядків у таблиці, ALTER TABLE оновлює рядки. ALTER TABLE отримує замок для зміни схеми (SCH-M) на столі, щоб переконатися, що під час зміни немає інших посилань на посилання навіть на метадані для таблиці., за винятком онлайнових операцій з індексом, які потребують дуже короткого блокування SCH-M в кінці. Під час операції «ALTER TABLE… SWITCH» блокування отримується як у вихідних, так і в цільових таблицях. Зміни, внесені до таблиці, записуються в систему та повністю підлягають відновленню. Зміни, що стосуються всіх рядків у дуже великих таблицях, наприклад, випадання стовпця або додавання стовпця NOT NULL зі значенням за замовчуванням у деяких виданнях SQL Server, може зайняти тривалий час для заповнення та генерації багатьох записів журналу. Ці оператори ALTER TABLE повинні виконуватися з такою ж обережністю, як і будь-які оператори INSERT, UPDATE або DELETE, які стосуються багатьох рядків.

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