Porque a hint (NOLOCK) gera locks

Não se engane: a hint NOLOCK pode causar locks em determinadas situações.

Em consultas no SQL Server é comum adicionarmos a hint (NOLOCK) para que a consulta seja feita no modo de isolamento READ UNCOMMITTED, ou seja, podendo ler dados que ainda estão sendo alterados em transações ainda não persistidas (ou “commitadas”), os chamados “dados sujos”.

Dessa forma você também não geraria locks e poderia rodar sua consulta sem impactar outras sessões. O problema é que nem sempre isso acontece. Para visualizar isso, primeiro vamos adicionar uma sessão de Extended Events monitorando o evento lock_acquired. Segue o código abaixo. Neste caso estou filtrando pelo id da sessão onde rodarei as demais queries:

CREATE EVENT SESSION [Lock_Acquired] ON SERVER 
 ADD EVENT sqlserver.lock_acquired(SET collect_resource_description=(1)
     ACTION(sqlserver.database_name,sqlserver.session_id,sqlserver.sql_text)
     WHERE ([sqlserver].[session_id]=(60)))
 ADD TARGET package0.event_file(SET filename=N'D:\SQLServer\Lock_Acquired.xel')
 GO
ALTER EVENT SESSION [Lock_Acquired] ON SERVER STATE = START
GO 

Em outra sessão vou rodar a seguinte query em uma base demo do StackOverflow (obrigado, Brent Ozar).

USE [StackOverflow2010]
GO

SELECT * FROM [Posts] [P] WITH (NOLOCK)
	WHERE [P].[Score] > 100

Agora voltemos à sessão do Extended Events:

Foram gerados vários locks no modo “SCH_S” (Schema Stability)

Esse tipo de lock (SCH-S) é utilizado para que não exista nenhum tipo de alteração estrutural na tabela enquanto sua query é compilada e executada, no entanto ele não bloqueia transações que utilizem locks transacionais. Ainda assim haverá bloqueio de operações que solicitem o lock “SCH-M” (schema modification) como por exemplo: ALTER TABLE, REBUILD, etc. É justo que isso aconteça, afinal de contas você não quer que alguém exclua a tabela ou uma coluna dela enquanto você a lê.

O caos (não) planejado

Vamos a uma situação hipotética:

Um dos desenvolvedores da empresa roda uma query na principal tabela do banco de dados da empresa e essa query vai buscar uma grande massa de dados, por isso ele utiliza a hint (NOLOCK).

SELECT * FROM [Posts] [P] WITH (NOLOCK)
	WHERE [P].[Score] > 1


Entretanto, enquanto a query do desenvolvedor A executava, o desenvolvedor B faz um deploy em produção (que já havia sido testado em desenvolvimento e homologação) para aumentar o tamanho de um campo VARCHAR.

ALTER TABLE [Posts] ALTER COLUMN Column1 VARCHAR(500)

Caos instaurado com sucesso pois enquanto aguarda a query do desenvolvedor A terminar, o ALTER TABLE do desenvolvedor B vai bloquear todas as transações subsequentes nessa tabela, até mesmo uma outra query com (NOLOCK). A situação será parecida com a seguinte (talvez seja bem pior dependendo do ambiente).

Conclusão

Neste post, vimos que é importante entender como funcionam os bloqueios em um banco de dados transacional para que determinadas situações desagradáveis possam ser evitadas.

Espero que tenham gostado e até a próxima.

Post criado 10

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Posts Relacionados

Comece a digitar sua pesquisa acima e pressione Enter para pesquisar. Pressione ESC para cancelar.

De volta ao topo