Блокировка Эскалации - Что здесь происходит? - PullRequest
126 голосов
/ 09 ноября 2009

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

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

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

Ответы [ 3 ]

158 голосов
/ 09 ноября 2009

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

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

Существует опция уровня таблицы, LOCK_ESCALATION, новая в SQL 2008, которая позволяет контролировать эскалацию блокировки. По умолчанию "TABLE" позволяет блокировкам увеличиваться до уровня таблицы. DISABLE предотвращает увеличение блокировки всей таблицы в большинстве случаев. AUTO разрешает блокировки таблиц, за исключением случаев, когда таблица секционирована, и в этом случае блокировки создаются только до уровня раздела. См. этот пост для получения дополнительной информации.

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

Также обратите внимание, что в SQL 2005 до появления этого параметра все блокировки могли перерасти в уровень таблицы - другими словами, "TABLE" был единственным параметром в SQL 2005.

9 голосов
/ 29 января 2016

Вы можете проверить, нужно ли включать оператор LOCK_ESCALATION в ваш скрипт, сравнив это значение до и после выполнения основной части вашего скрипта:

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

В моем случае изменение таблицы для удаления или добавления ограничения, по-видимому, не изменяет это значение.

5 голосов
/ 19 сентября 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...