В ответе Джастина Гранта объясняется, что вообще делает настройка 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, блокировка получается на обоих источниках
и целевые таблицы. Внесенные в таблицу изменения регистрируются и
полностью восстанавливаемый. Изменения, которые затрагивают все строки в очень большом
таблицы, такие как удаление столбца или, в некоторых выпусках SQL Server,
добавление столбца NOT NULL со значением по умолчанию может занять много времени для
завершить и создать много записей журнала. Эти операторы ALTER TABLE
должен выполняться с той же тщательностью, что и любой INSERT, UPDATE или DELETE
оператор, который влияет на многие строки.