Блокировка Эскалации - Что здесь происходит?

138

Изменяя таблицу (удаляя столбец) в SQL Server 2008, я нажал кнопку «Создать сценарий изменения» и заметил, что созданный сценарий изменения удаляет столбец, говорит «go», а затем запускает дополнительный оператор ALTER TABLE, который, кажется, устанавливает эскалация блокировки таблицы до «TABLE». Пример:

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

Я должен также отметить, что это последнее, что делает скрипт изменения. Что он здесь делает и почему он устанавливает LOCK_ESCALATION в TABLE?

Джеймс Александр
источник

Ответы:

165

« Lock Escalation » - это то, как SQL обрабатывает блокировку для больших обновлений. Когда SQL собирается изменить много строк, для механизма базы данных более эффективно брать меньше больших блокировок (например, всей таблицы) вместо блокирования множества более мелких вещей (например, блокировок строк).

Но это может быть проблематично, если у вас огромная таблица, потому что блокировка всей таблицы может на долгое время блокировать другие запросы. Это компромисс: многие блокировки с малой гранулярностью работают медленнее, чем меньшее количество (или одна) грубых блокировок, а наличие нескольких запросов, блокирующих разные части таблицы, создает возможность тупиковой блокировки, если один процесс ожидает другого.

В LOCK_ESCALATIONSQL 2008 есть новая опция уровня таблицы , которая позволяет контролировать эскалацию блокировки. По умолчанию "TABLE" позволяет блокировкам увеличиваться до уровня таблицы. 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, который влияет на множество строк.

Владимир Баранов
источник