A resposta de Justin Grant explica o que a LOCK_ESCALATION
configuração faz em geral, mas perde um detalhe importante e não explica por que o SSMS gera o código que a define. Especialmente, parece muito estranho que isso LOCK_ESCALATION
seja definido como uma última declaração no script.
Fiz alguns testes e aqui está o meu entendimento do que está acontecendo aqui.
Versão curta
A ALTER TABLE
instrução que adiciona, elimina ou altera uma coluna implica implicitamente um bloqueio de modificação de esquema (SCH-M) na tabela, que nada tem a ver com a LOCK_ESCALATION
configuração de uma tabela. LOCK_ESCALATION
afecta o comportamento de bloqueio durante as instruções DML ( INSERT
, UPDATE
, DELETE
, etc.), e não durante as instruções de DDL (ALTER
). O bloqueio SCH-M é sempre um bloqueio de todo o objeto de banco de dados, tabela neste exemplo.
Provavelmente é de onde vem a confusão.
O SSMS adiciona a ALTER TABLE <TableName> SET (LOCK_ESCALATION = ...)
declaração ao seu script em todos os casos, mesmo quando não é necessário. Nos casos em que essa instrução é necessária, ela é adicionada para preservar a configuração atual da tabela, não para bloquear a tabela de alguma maneira específica durante a alteração no esquema da tabela. que ocorre nesse script.
Em outras palavras, a tabela é bloqueada com o bloqueio SCH-M na primeira ALTER TABLE ALTER COLUMN
instrução, enquanto todo o trabalho de alteração do esquema da tabela é realizado. A última ALTER TABLE SET LOCK_ESCALATION
declaração não afeta. Ela afeta apenas futuros instruções DML ( INSERT
, UPDATE
,DELETE
, etc.) para a tabela.
À primeira vista, parece que SET LOCK_ESCALATION = TABLE
ter algo a ver com o fato de estarmos alterando a tabela inteira (estamos alterando seu esquema aqui), mas é enganoso.
Versão longa
Ao alterar a tabela em alguns casos, o SSMS gera um script que recria a tabela inteira e, em alguns casos mais simples (como adicionar ou soltar uma coluna), o script não recria a tabela.
Vamos pegar esta tabela de exemplo como exemplo:
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
Cada tabela possui uma LOCK_ESCALATION
configuração, definida TABLE
por padrão. Vamos mudar aqui:
ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)
Agora, se eu tentar alterar o Col1
tipo no designer da tabela SSMS, o SSMS gerará um script que recria a tabela inteira:
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
Você pode ver acima que ele define LOCK_ESCALATION
para a tabela recém-criada. O SSMS faz isso para preservar a configuração atual da tabela. O SSMS gera essa linha, mesmo que o valor atual da configuração seja o TABLE
valor padrão . Apenas para ser seguro, explícito e evitar possíveis problemas futuros, se no futuro esse padrão mudar, eu acho. Isso faz sentido.
Neste exemplo, é realmente necessário gerar a SET LOCK_ESCALATION
instrução, porque a tabela é criada novamente e sua configuração deve ser preservada.
Se eu tentar fazer uma alteração simples na tabela usando o designer de tabelas SSMS, como adicionar uma nova coluna, o SSMS gerará um script que não recriará a tabela:
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
Como você pode ver, ele ainda adiciona a ALTER TABLE SET LOCK_ESCALATION
declaração, embora neste caso não seja necessária. O primeiro ALTER TABLE ... ADD
não altera a configuração atual. Acho que os desenvolvedores do SSMS decidiram que não vale a pena tentar determinar em que casos essa ALTER TABLE SET LOCK_ESCALATION
declaração é redundante e gerá-la sempre, apenas para garantir a segurança. Não há mal nenhum em adicionar esta declaração sempre.
Mais uma vez, a LOCK_ESCALATION
configuração de toda a tabela é irrelevante enquanto o esquema da tabela é alterado por meio da ALTER TABLE
instrução LOCK_ESCALATION
A configuração afeta apenas o comportamento de bloqueio das instruções DML, comoUPDATE
.
Finalmente, uma citação de ALTER TABLE
, enfatize a minha:
As alterações especificadas em ALTER TABLE são implementadas imediatamente. Se as alterações exigirem modificações nas linhas da tabela, ALTER TABLE atualizará as linhas. ALTER TABLE adquire um bloqueio de modificação de esquema (SCH-M) na tabela para garantir que nenhuma outra conexão faça referência aos metadados da tabela durante a alteração, exceto operações de índice online que exigem um bloqueio SCH-M muito curto no final. Em uma operação ALTER TABLE… SWITCH, o bloqueio é adquirido nas tabelas de origem e de destino. As modificações feitas na tabela são registradas e totalmente recuperáveis. Alterações que afetam todas as linhas em tabelas muito grandes, como descartar uma coluna ou, em algumas edições do SQL Server, adicionar uma coluna NOT NULL com um valor padrão, podem levar muito tempo para concluir e gerar muitos registros de log. Essas instruções ALTER TABLE devem ser executadas com o mesmo cuidado que qualquer instrução INSERT, UPDATE ou DELETE que afeta muitas linhas.