Escalonamento de bloqueio - O que está acontecendo aqui?

138

Ao alterar uma tabela (remover uma coluna) no SQL Server 2008, cliquei no botão Gerar script de alteração e notei que o script de alteração gerado solta a coluna, diz "ir" e depois executa uma instrução ALTER TABLE adicional que parece definir a escalação de bloqueio da tabela para "TABLE". Exemplo:

ALTER TABLE dbo.Contract SET (LOCK_ESCALATION = TABLE)

Devo também observar que esta é a última coisa que o script de mudança está fazendo. O que está fazendo aqui e por que está configurando LOCK_ESCALATION para TABLE?

James Alexander
fonte

Respostas:

165

" Escalonamento de bloqueio " é como o SQL lida com o bloqueio para atualizações grandes. Quando o SQL muda muitas linhas, é mais eficiente para o mecanismo de banco de dados receber menos bloqueios maiores (por exemplo, tabela inteira) em vez de bloquear muitas coisas menores (por exemplo, bloqueios de linha).

Mas isso pode ser problemático quando você tem uma tabela enorme, porque bloquear uma tabela inteira pode bloquear outras consultas por um longo tempo. Essa é a desvantagem: muitos bloqueios de granularidade pequena são mais lentos que menos (ou um) bloqueios de granulação grossa, e ter várias consultas bloqueando diferentes partes de uma tabela cria a possibilidade de conflito se um processo estiver aguardando no outro.

Existe uma opção no nível da tabela LOCK_ESCALATION, nova no SQL 2008, que permite o controle da escalação de bloqueios. O padrão "TABLE" permite que os bloqueios sejam escalados até o nível da tabela. DISABLE evita o escalonamento de bloqueios para a tabela inteira na maioria dos casos. AUTO permite bloqueios de tabela, exceto se a tabela for particionada; nesse caso, os bloqueios são feitos apenas no nível da partição. Veja esta postagem no blog para obter mais informações.

Suspeito que o IDE adicione essa configuração ao recriar uma tabela porque TABLE é o padrão no SQL 2008. Observe que LOCK_ESCALATION não é suportado no SQL 2005, portanto, você precisará removê-lo se tentar executar o script em um Instância de 2005. Além disso, como TABLE é o padrão, você pode remover com segurança essa linha ao executar novamente seu script.

Observe também que, no SQL 2005 antes que essa configuração estivesse presente, todos os bloqueios podiam ser escalados para o nível da tabela - em outras palavras, "TABLE" era a única configuração no SQL 2005.

Justin Grant
fonte
1
Pós duplicado nos fóruns do MSDN também: social.msdn.microsoft.com/Forums/en-US/sqldatabaseengine/thread/...
Jonathan Kehayias
6
@dma_k - Esta opção não é relevante CREATE TABLEporque a tabela ainda não existe, portanto não há nada para bloquear.
Justin Grant
1
Mas por que a instrução LOCK_ESCALATION após a instrução ALTER TABLE inicial no script de alteração ao criar uma tabela no SSMS? Certamente, nessa época, o trabalho já estava feito. Não deveria ser antes de alterar a estrutura da tabela?
Reversed Engineer
2
@DaveBoltman - o SET faz parte da instrução ALTER TABLE. Não é uma afirmação separada. Consulte docs.microsoft.com/en-us/sql/t-sql/statements/…
Justin Grant
2
JustinGrant, ainda assim, a pergunta de @DaveBoltman permanece. O script que o SSMS gera para, digamos, adicionar uma nova coluna possui duas ALTER TABLEinstruções separadas . Primeiro ALTER TABLE ADD column, depois GO, depois segundo ALTER TABLE SET LOCK_ESCALATION=TABLE, depois segundo GO. Então, LOCK_ESCALATIONé definido após a coluna ser adicionada. Qual o sentido de defini-lo após o fato? Essas duas ALTER TABLEinstruções são agrupadas em uma transação, mas ainda assim a coluna é adicionada antes da LOCK_ESCALATIONdefinição. Acho que vou aprofundar um pouco mais e escrever outra resposta.
Vladimir Baranov
11

Você pode verificar se precisa incluir a instrução LOCK_ESCALATION em seu script comparando esse valor antes e depois de executar a parte principal do seu script:

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

No meu caso, alterar a tabela para eliminar ou adicionar uma restrição não parece modificar esse valor.

Bogdan Verbenets
fonte
11

A resposta de Justin Grant explica o que a LOCK_ESCALATIONconfiguraçã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_ESCALATIONseja 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 TABLEinstruçã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_ESCALATIONconfiguração de uma tabela. LOCK_ESCALATIONafecta 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 COLUMNinstrução, enquanto todo o trabalho de alteração do esquema da tabela é realizado. A última ALTER TABLE SET LOCK_ESCALATIONdeclaraçã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_ESCALATIONconfiguração, definida TABLEpor padrão. Vamos mudar aqui:

ALTER TABLE dbo.Test SET (LOCK_ESCALATION = DISABLE)

Agora, se eu tentar alterar o Col1tipo 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_ESCALATIONpara 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 TABLEvalor 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_ESCALATIONinstruçã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_ESCALATIONdeclaração, embora neste caso não seja necessária. O primeiro ALTER TABLE ... ADDnã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_ESCALATIONdeclaraçã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_ESCALATIONconfiguração de toda a tabela é irrelevante enquanto o esquema da tabela é alterado por meio da ALTER TABLEinstrução LOCK_ESCALATIONA 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.

Vladimir Baranov
fonte