Ответ Джастина Гранта объясняет, что 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, который влияет на множество строк.