A ideia principal do mecanismo de bloqueio do SQL Server é que ele controla a consistência das transações. De acordo com esse princípio, se um processo deseja executar operações de inserção, exclusão ou atualização, o mecanismo do SQL Server bloqueia a linha ou linhas e não permite outro processo até que a transação seja concluída. Em algumas circunstâncias, esse mecanismo de travamento pode levar a problemas de desempenho, como altas pressões de processo simultâneas. Assim, você pode experimentar os problemas de deadlock (Deadlock é um problema de simultaneidade em que duas transações desejam acessar os mesmos dados simultaneamente) em seu banco de dados. Neste artigo, vamos nos concentrar em como evitar problemas de bloqueio com a ajuda da dica NOLOCK. Primeiro, vamos aprender os principais fundamentos e detalhes da metodologia de leitura suja, pois a dica NOLOCK pode causar leitura suja.
Leitura suja: Nesta metodologia de leitura, o processo de leitura lê dados não confirmados e o processo de leitura não se preocupa com transações abertas, portanto, os bloqueios não causam problemas no processo de leitura. Como resultado, esse tipo de leitura reduz os problemas de travamento. No entanto, a metodologia de leitura suja tem prós e contras porque a leitura suja pode causar problemas de inconsistência no conjunto de resultados da instrução SELECT. Como já mencionado, esses conjuntos de resultados podem incluir dados de transações não confirmadas, por isso temos que considerar a leitura suja ao decidir fazer esse tipo de leitura. Não podemos ter certeza sobre a precisão das linhas que criamos durante a leitura suja porque essas linhas podem ser revertidas. Por outro lado, esse tipo de leitura nos permite evitar problemas de travamento e aumentar o desempenho do SQL Server.
NOLOCK: O nível de isolamento padrão do SQL Server é Read Committed e, nesse nível de isolamento, o SQL Server não permite ler objetos bloqueados que estão bloqueados por transações não confirmadas. Além disso, esses objetos bloqueados podem ser alterados de acordo com o escalonamento de bloqueios.
Observação:neste artigo Conceito principal de bloqueio do SQL Server, você pode encontrar detalhes sobre bloqueio e escalonamento de bloqueio.
Imagine que você tem dois usuários de banco de dados e esses usuários desejam executar a operação de atualização e seleção no banco de dados. Um primeiro usuário começa a atualizar uma linha específica na tabela e, em seguida, o outro usuário deseja ler a mesma linha. Esses dois usuários executam as seguintes instruções de atualização e seleção, ilustradas na imagem abaixo.
Neste caso, user2 espera pelo menos 10 segundos e então a transação será revertida por user1, e então user2 pode ler a linha verde porque a linha bloqueada será liberada por user1. Este é o comportamento padrão do nível de isolamento do SQL Server Read Committed.
Agora, vamos demonstrar este caso no SQL Server. Em primeiro lugar, criaremos a tabela FruitSales e suas linhas.
CREATE TABLE FruitSales (Id INT IDENTITY (1,1) PRIMARY KEY, [Name] Varchar(20) , SalesTotal Float) GO INSERT INTO FruitSales VALUES ('Apple',10) ,('Orange',8), ('Banana',2)
Nesta etapa, abriremos duas janelas de consulta do SQL Server Management Studio e executaremos a consulta user1 e, em seguida, executaremos a consulta user2.
---USER1---- BEGIN TRAN UPDATE FruitSales SET SalesTotal =20 WHERE Id=2 WAITFOR DELAY '00:00:10' ROLLBACK TRANSACTION ---USER2---- SET STATISTICS TIME ON SELECT * FROM FruitSales WHERE Id=2
Como você pode ver na imagem acima, a segunda consulta aguarda até o rollback da transação user1.
Agora, discutiremos a dica do NOLOCK e os detalhes de uso. A dica NOLOCK é a dica de tabela mais popular que é usada por desenvolvedores e administradores de banco de dados para eliminar problemas de bloqueio em bancos de dados SQL Server. Com a ajuda da dica de tabela NOLOCK, podemos ler objetos bloqueados (linha, página ou tabela) que estão bloqueados por transações abertas. A dica NOLOCK substitui o comportamento padrão do otimizador de consulta do SQL Server para que a instrução select possa ler os objetos bloqueados.
Agora, adicionaremos a dica NOLOCK à instrução de seleção do usuário2 e, em seguida, iniciaremos a atualização do usuário1 e, em seguida, executaremos a instrução de seleção do usuário2.
---USER1---- BEGIN TRAN UPDATE FruitSales SET SalesTotal =20 WHERE Id=2 WAITFOR DELAY '00:00:10' ROLLBACK TRANSACTION ---USER2---- SET STATISTICS TIME ON SELECT * FROM FruitSales WITH(NOLOCK) WHERE Id=2
Nesta etapa, explicaremos como impactar a dica NOLOCK na instrução user2 select. User1 executa a instrução atualizada em uma transação explícita e, em seguida, user2 executa a instrução select e o conjunto de resultados retorna sem demora a conclusão da transação. Esta é a ideia principal do NOLOCK, ele lê objetos bloqueados.
Agora, vamos nos concentrar no conjunto de resultados da instrução select. A instrução user2 select recuperou o valor SalesTotal 20, mas o valor real de SalesTotal ainda é 8. Lembre-se de que, se você estiver usando a dica de tabela NOLOCK em sua instrução select, poderá enfrentar esse tipo de resultados de dados imprecisos.
Dica: A palavra-chave “WITH” é um recurso obsoleto, portanto, a Microsoft recomenda não usá-la em seu novo desenvolvimento de banco de dados e remover a palavra-chave “WITH” em seus desenvolvimentos atuais. Você pode encontrar o uso da dica NOLOCK sem a palavra-chave “WITH”.
---USER1---- BEGIN TRAN UPDATE FruitSales SET SalesTotal =20 WHERE Id=2 WAITFOR DELAY '00:00:10' ROLLBACK TRANSACTION SELECT * FROM FruitSales WHERE Id=2 --USER2--- SELECT * FROM FruitSales (NOLOCK) WHERE Id=2
Além disso, a dica de tabela READUNCOMMITTED é equivalente à dica NOLOCK e podemos usar a dica READUNCOMMITTED em vez da dica NOLOCK.
SELECT * FROM FruitSales (READUNCOMMITTED) WHERE Id=2
Mesmo assim, há um caso particular sobre a dica NOLOCK que não consegue passar pela barreira de travamento. Se houver algum processo alterando uma tabela, a dica NOLOCK não poderá superar esse tipo de bloqueio e não poderá continuar a operação de leitura. A razão para esse problema é que a dica NOLOCK adquire o bloqueio Sch-S (estabilidade de esquema) e a instrução ALTER TABLE adquire o bloqueio SCH-M (modificação de esquema), portanto, ocorre um conflito.
A princípio, aprenderemos a tabela Object_Id da FruitSales com a ajuda da consulta a seguir.
select OBJECT_ID('FruitSales')
Execute a seguinte consulta user1 e, em seguida, execute a consulta user2. Como resultado, a consulta user2 atrasará a conclusão do processo de alteração da tabela user1.
--USER1--- BEGIN TRAN ALTER TABLE FruitSales ADD ColorofFruit varchar(200) WAITFOR DELAY '00:00:35 GO COMMIT TRAN --USER2--- SELECT * FROM FruitSales (NOLOCK) WHERE Id=2
Abra a nova janela de consulta e execute a seguinte consulta. Esta consulta ajudará a descobrir o tipo de bloqueio das consultas user1 e user2.
SELECT Resource_type, Resource_database_id, Resource_description, Resource_associated_entity_id, Resource_lock_partition, Request_mode, Request_type, Request_status, Request_session_id, Request_request_id, Request_owner_type, Request_owner_id, Lock_owner_address FROM sys.dm_tran_locks where resource_associated_entity_id =647673355
Agora, vamos verificar a matriz de compatibilidade de bloqueio para interação SCH-M e SCH-S. A matriz descreve que a interação SCH-M e SCH-S causa um conflito.
Conclusão
Neste artigo, mencionamos o processo de leitura suja e a dica NOLOCK. Usar a dica NOLOCK é um método eficaz para ler uma página bloqueada, mas também tem algumas vantagens e desvantagens. Por esta razão, você deve considerar a dica NOLOCK antes de usá-la.
Referências
Guia de controle de versão de linha e bloqueio de transações do SQL Server
Dicas (Transact-SQL) – Tabela
SET TRANSACTION ISOLATION LEVEL (Transact-SQL)