O que é "with (nolock)" no SQL Server?

610

Alguém pode explicar as implicações do uso with (nolock)em consultas, quando você deve / não deve usá-lo?

Por exemplo, se você tiver um aplicativo bancário com altas taxas de transação e muitos dados em determinadas tabelas, em que tipos de consultas o nolock seria bom? Existem casos em que você sempre deve usá-lo / nunca usá-lo?

Andy White
fonte
I subquestioned em stackoverflow.com/questions/3836282/... e stackoverflow.com/questions/3836032/... principalmente a resposta de Jonathan Allen stackoverflow.com/questions/686724/...
Gennady Vanin Геннадий Ванин
1
um link aqui - mssqltips.com/sqlservertip/2470/…
Steam
1
Aqui é um excelente resumo das implicações do uso NOLOCK blogs.msdn.com/b/davidlean/archive/2009/04/06/...
Bryan

Respostas:

461

WITH (NOLOCK) é o equivalente a usar READ UNCOMMITED como um nível de isolamento de transação. Portanto, você corre o risco de ler uma linha não confirmada que é posteriormente revertida, ou seja, dados que nunca chegaram ao banco de dados. Portanto, embora possa impedir que as leituras sejam bloqueadas por outras operações, ela apresenta um risco. Em um aplicativo bancário com altas taxas de transação, provavelmente não será a solução certa para qualquer problema que você esteja tentando resolver com ele IMHO.

David M
fonte
156
A maioria dos aplicativos bancários pode usar o nolock com segurança porque são transacionais no sentido comercial. Você escreve apenas novas linhas, nunca as atualiza.
31139 Jonathan Allen
49
@ Grauenwolf- Uma linha inserida, mas não confirmada, ainda pode levar a leituras sujas.
saasman
16
@ Saasman- Se você nunca reverter transações, isso não importa. E com uma tabela somente de inserção, as chances de uma reversão são reduzidas a zero. E se ocorrerem, você ainda corrigirá tudo no relatório de variação do final do dia.
27139 Jonathan Allen as
1
Eu estou entrincheirado. Eu suponho que o Adicionado sem dicas de bloqueio. Para Examp:
Ross Bush,
11
Se você usar NOLOCKcom a, SELECTcorre o risco de retornar as mesmas linhas mais de uma vez (dados duplicados) se os dados forem inseridos (ou atualizados) na tabela ao fazer uma seleção.
22613 Ian Boyd
170

A questão é o que é pior:

  • um impasse ou
  • um valor errado?

Para bancos de dados financeiros, os impasses são muito piores que os valores errados. Eu sei que isso soa ao contrário, mas ouça. O exemplo tradicional de transações de banco de dados é atualizar duas linhas, subtraindo de uma e adicionando a outra. Isso esta errado.

Em um banco de dados financeiro, você usa transações comerciais. Isso significa adicionar uma linha a cada conta. É de extrema importância que essas transações sejam concluídas e as linhas sejam gravadas com êxito.

Colocar o saldo da conta temporariamente errado não é grande coisa, é para isso que serve a reconciliação do final do dia. E um cheque especial de uma conta é muito mais provável de ocorrer porque dois caixas eletrônicos estão sendo usados ​​ao mesmo tempo do que por causa de uma leitura não confirmada de um banco de dados.

Dito isto, o SQL Server 2005 corrigiu a maioria dos bugs NOLOCKnecessários. Portanto, a menos que você esteja usando o SQL Server 2000 ou anterior, não será necessário.

Leitura adicional
Versão em nível de linha

Jonathan Allen
fonte
22
Obter um saldo temporariamente errado da conta não é grande coisa? E se essa transação for aquela em que você está retirando dinheiro de um caixa eletrônico sem nenhum limite de cheque especial?
Aprendendo
13
@ Learning: O que acontece se você retirar o dinheiro 30 segundos antes de alguém cobrar seu cartão? Até que toda a comunicação seja imediata, os saques a descoberto serão um fato da vida.
27139 Jonathan Allen
6
+1 No aplicativo financeiro (em todos os lugares, não apenas nos bancos), não há atualizações nem exclusões. Até operações incorretas são corrigidas através da inserção de registros. Qual é esse termo em inglês? É "storno"? O Google não me ajudou a responder a esta pergunta
Gennady Vanin Геннадий Ванин
7
Entrada tardia ... os bloqueios devem ser capturados e repetidos. Leituras sujas têm consequências
gbn
4
@ JonathanAllen apenas um ano, o termo é UTmost, não UP.
Jimmy D
57

Infelizmente, não se trata apenas de ler dados não confirmados. Em segundo plano, você pode acabar lendo as páginas duas vezes (no caso de uma divisão de página) ou pode perder totalmente as páginas. Portanto, seus resultados podem ficar totalmente distorcidos.

Confira o artigo de Itzik Ben-Gan . Aqui está um trecho:

"Com a dica NOLOCK (ou definindo o nível de isolamento da sessão como LIDO SEM COMPROMISSO), você diz ao SQL Server que não espera consistência, portanto não há garantias. Lembre-se de que" dados inconsistentes "não significa apenas que você poderá ver alterações não confirmadas que foram revertidas posteriormente ou alterações de dados em um estado intermediário da transação , o que também significa que, em uma consulta simples que varre todos os dados de tabela / índice, o SQL Server pode perder a posição de verificação ou você pode acabar recebendo a mesma linha duas vezes . "

sqlbelle
fonte
5
Um pouco mais abaixo, ele explica como obter a mesma linha duas vezes: vou recriar a tabela T1 para que o índice clusterizado em col1 seja definido como um índice exclusivo com a opção IGNORE_DUP_KEY. Isso significa que valores duplicados não podem existir em col1 e também que uma tentativa de inserir uma chave duplicada não falhará na transação e gerará um erro, apenas gerará um aviso. Se você não usar esta opção estranho você provavelmente não precisa se preocupar sobre a obtenção de linhas duas vezes
JanHudecek
Você ainda pode obter linhas duplas, mesmo sem a opção com fio - se sua consulta alavancar um índice que não seja exclusivo, por exemplo. Isso não é exclusivo da nolock, no entanto.
RMD
54

O exemplo do livro de texto para uso legítimo da dica nolock é a amostragem de relatórios em um banco de dados OLTP de alta atualização.

Para dar um exemplo tópico. Se um grande banco de rua dos EUA quisesse executar um relatório por hora procurando os primeiros sinais de uma corrida no nível da cidade, uma consulta nolock poderia examinar as tabelas de transações, somando depósitos e retiradas de dinheiro por cidade. Para esse relatório, a pequena porcentagem de erro causada pelas transações de atualização revertida não reduziria o valor do relatório.

saasman
fonte
31

Não sei por que você não está agrupando transações financeiras em transações de banco de dados (como quando você transfere fundos de uma conta para outra - você não confirma um lado da transação por vez - é por isso que existem transações explícitas). Mesmo se o seu código estiver relacionado às transações comerciais como parece, todos os bancos de dados transacionais podem fazer reversões implícitas no caso de erros ou falhas. Eu acho que essa discussão está bem acima da sua cabeça.

Se você estiver com problemas de bloqueio, implemente a versão e limpe seu código.

Nenhum bloqueio não apenas retorna valores errados, mas também devolve registros e duplicações fantasmas.

É um equívoco comum que sempre faça com que as consultas sejam executadas mais rapidamente. Se não houver bloqueios de gravação em uma tabela, isso não fará nenhuma diferença. Se houver bloqueios na tabela, isso poderá agilizar a consulta, mas existe um motivo pelo qual os bloqueios foram inventados.

Para ser justo, aqui estão dois cenários especiais em que uma dica nolock pode fornecer utilidade

1) Banco de dados do servidor sql anterior a 2005 que precisa executar uma consulta longa no banco de dados OLTP ativo, essa pode ser a única maneira

2) Aplicativo mal escrito que bloqueia registros e retorna o controle para a interface do usuário e os leitores são bloqueados indefinidamente. O Nolock pode ser útil aqui se o aplicativo não puder ser corrigido (terceiros etc.) e o banco de dados for anterior a 2005 ou o controle de versão não puder ser ativado.

Andrew
fonte
11
Concordo com você que o NOLOCK não deve ser usado para compensar códigos mal escritos. No entanto, acho que seu ataque a Johnathan é injustificado, pois ele nunca mencionou transações de banco de dados . Ele estava simplesmente apontando que os aplicativos financeiros normalmente não permitem edições nos registros (obviamente existem algumas exceções). No seu exemplo de transferência de fundos, ele está dizendo que seria estranho alterar o valor do saldo da conta em vez de adicionar uma entrada de débito / crédito a uma espécie de razão.
Chrnola
19
Quando os fundos são transferidos de uma conta para outra em bancos diferentes, o que você acha que acontece? Algum uber-banco de dados trava uma mesa no Bank of America e outra no Wells Fargo? Não. Uma transação financeira é gravada em cada um e, em seguida, um processo de final do dia verifica se todos os registros correspondem.
Jonathan Allen
24

NOLOCKé equivalente a READ UNCOMMITTED, no entanto, a Microsoft diz que você não deve usá-lo para UPDATEou DELETEdeclarações:

Para instruções UPDATE ou DELETE: Esse recurso será removido em uma versão futura do Microsoft SQL Server. Evite usar esse recurso em novos trabalhos de desenvolvimento e planeje modificar os aplicativos que atualmente usam esse recurso.

http://msdn.microsoft.com/en-us/library/ms187373.aspx

Este artigo se aplica ao SQL Server 2005, portanto, o suporte a NOLOCKexiste se você estiver usando essa versão. Para garantir a codificação futura (assumindo que você decidiu usar leituras sujas), você pode usar isso nos procedimentos armazenados:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

Seibar
fonte
21

Você pode usá-lo quando está lendo apenas dados e realmente não se importa se está ou não recebendo dados que ainda não foram confirmados.

Pode ser mais rápido em uma operação de leitura, mas não sei dizer em quanto.

Em geral, eu recomendo não usá-lo - a leitura de dados não confirmados pode ser um pouco confusa, na melhor das hipóteses.

marc_s
fonte
1
seria bom se você mencionasse o fato de que o SQL Server 2005 possui controle de versão de linha, para que os nolocks não sejam mais necessários.
3113 Jonathan Allen
Bem, o "with (nolock)" ainda tem seu lugar até no SQL Server 2005 - mas os benefícios estão ficando cada vez menores, isso é verdade.
26323 marc_s
18

Outro caso em que geralmente está bom é em um banco de dados de relatórios, onde os dados talvez já estejam antigos e as gravações simplesmente não acontecem. Nesse caso, porém, a opção deve ser definida no banco de dados ou no nível da tabela pelo administrador, alterando o nível de isolamento padrão.

No caso geral: você pode usá-lo quando você está muito certo de que não há problema em ler dados antigos. O importante é lembrar que é muito fácil entender errado . Por exemplo, mesmo que esteja tudo bem no momento em que você escrever a consulta, você tem certeza de que algo não será alterado no banco de dados no futuro para tornar essas atualizações mais importantes?

Também vou entender a noção de que provavelmente não é uma boa ideia no aplicativo bancário. Ou aplicativo de inventário. Ou em qualquer lugar que você esteja pensando em transações.

Joel Coehoorn
fonte
4
Como uma pessoa que trabalha em aplicativos bancários, devo dizer que o bloqueio não é um problema. Os registros transacionais, ou seja, linhas inseridas, mas nunca atualizadas ou excluídas, são surpreendentemente resistentes aos problemas de leitura de dados não confirmados.
3113 Jonathan Allen
15

Resposta simples - sempre que seu SQL não estiver alterando dados, e você tiver uma consulta que possa interferir em outras atividades (via bloqueio).

Vale a pena considerar todas as consultas usadas para relatórios, especialmente se a consulta demorar mais de, por exemplo, 1 segundo.

É especialmente útil se você tiver relatórios do tipo OLAP em execução em um banco de dados OLTP.

A primeira pergunta a ser feita, porém, é "por que estou me preocupando com isso?" Na minha experiência, a falsificação do comportamento de bloqueio padrão geralmente ocorre quando alguém está no modo "tente qualquer coisa" e esse é um caso em que conseqüências inesperadas não são improváveis. Muitas vezes, é um caso de otimização prematura e pode ser facilmente incorporado em um aplicativo "apenas por precaução". É importante entender por que você está fazendo isso, qual problema ele resolve e se você realmente tem o problema.

dkretz
fonte
11

Resposta curta:

Use apenas WITH (NOLOCK)na instrução SELECT em tabelas que possuem um índice em cluster.

Resposta longa:

WITH (NOLOCK) é frequentemente explorado como uma maneira mágica de acelerar leituras de banco de dados.

O conjunto de resultados pode conter linhas que ainda não foram confirmadas, que geralmente são revertidas posteriormente.

Se WITH (NOLOCK) for aplicado a uma tabela que possui um índice não clusterizado, os índices de linha poderão ser alterados por outras transações, à medida que os dados da linha estiverem sendo transmitidos para a tabela de resultados. Isso significa que o conjunto de resultados pode estar faltando linhas ou exibir a mesma linha várias vezes.

READ COMMITTED adiciona um problema adicional em que os dados são corrompidos em uma única coluna em que vários usuários alteram a mesma célula simultaneamente.

WonderWorker
fonte
2
A leitura de dados não confirmados é aceitável se não alterar a decisão final. Por exemplo, se você está tentando projetar quanto dinheiro sua loja vai ganhar nos próximos 6 meses, uma vez que Tammy comprou 2 rolos de papel toalha quando realmente comprou 3 não vai mudar sua opinião sobre o futuro .
Jonathan Allen
1
Se o seu filtro incluir agora, seus dados serão imprecisos no momento em que você executar a consulta. Se o seu filtro incluir apenas dados históricos, o uso READ UNCOMITTED não o afetará. Há uma razão pela qual foi incluída no padrão ANSI.
Jonathan Allen
2
Nunca diga nunca. Se você PRECISA que os dados sejam 100% precisos, não deve usar o nolock. Para mim, isso geralmente não é o caso. Ao apresentar dados para um usuário, no momento em que eles agem sobre os dados, ele já pode ter sido alterado de qualquer maneira, mas provavelmente não mudou, e a contenção do bloqueio não vale os atrasos na resposta.
Perposterer
Vamos nos ater a sistemas dignos de existência. Não se esqueça que Tammy tem um cérebro perfeitamente decente; portanto, use um banco de dados para registrar pequenas compras de toalhas de papel das quais ninguém percebe nada absurdo. Nosso foco são sistemas que são realmente importantes, por exemplo, receber pessoas pagas a tempo, responder a emergências etc. É um benefício significativo que o uso de WITH (NOLOCK) seja entendido pelas pessoas que programam qualquer sistema digno de existir. Quando uma pessoa pode fazer um trabalho melhor do que um banco de dados, considere redirecionar esses recursos.
WonderWorker
10

Meus 2 centavos - faz sentido usar WITH (NOLOCK) quando você precisa gerar relatórios. Nesse ponto, os dados não mudariam muito e você não gostaria de bloquear esses registros.

SoftwareGeek
fonte
2
Eu acho que WITH (NoLOCK) é melhor se você não se importa com as mudanças atuais.
Abdul Saboor 11/03/2013
9

Se você estiver lidando com transações financeiras, nunca desejará usá-lo nolock. nolocké melhor usado para selecionar tabelas grandes com muitas atualizações e você não se importa se o registro obtido pode estar desatualizado.

Os registros financeiros (e quase todos os outros registros na maioria dos aplicativos) nolockcausariam estragos, pois você poderia ler os dados de um registro que estava sendo gravado e não obter os dados corretos.

Andrew Hare
fonte
5
Surpreendentemente, ao trabalhar com dados financeiros, isso não é um problema. Como as linhas nunca são editadas e as contas são reconciliadas no final do dia, a leitura temporária de dados falsos não faz nada.
24139 Jonathan Allen
8

Eu costumava recuperar um "próximo lote" para o que fazer. Nesse caso, não importa qual item exato, e eu tenho muitos usuários executando essa mesma consulta.

Otávio Décio
fonte
1
Fazemos algo semelhante para apresentar uma tarefa em segundo plano com uma fila de trabalho a ser executada. Se, quando chegar a um registro específico, ele não existir mais / corresponder aos critérios de seleção, ele passará para o próximo.
TripeHound
7

Use nolock quando estiver de acordo com os dados "sujos". O que significa que o nolock também pode ler dados que estão em processo de modificação e / ou dados não confirmados.

Geralmente, não é uma boa ideia usá-lo em ambientes de alta transação e é por isso que não é uma opção padrão na consulta.

Aprendendo
fonte
3
O único momento necessário é em um ambiente de alta transação. Se suas mesas estiverem ociosas, você não ganhará nada com isso.
3113 Jonathan Allen
7

Eu uso com a dica (nolock) particularmente nos bancos de dados SQLServer 2000 com alta atividade. Não tenho certeza de que seja necessário no SQL Server 2005. Recentemente, eu adicionei essa dica no SQL Server 2000 a pedido do DBA do cliente, porque ele estava percebendo muitos bloqueios de registros SPID.

Tudo o que posso dizer é que o uso da dica NÃO nos machucou e parece ter feito o problema de travamento se resolver. O DBA naquele cliente em particular basicamente insistiu em usar a dica.

A propósito, os bancos de dados com os quais lido são back-end para sistemas de reclamações médicas corporativas, por isso estamos falando de milhões de registros e mais de 20 tabelas em muitas associações. Normalmente, adiciono uma dica WITH (nolock) para cada tabela na junção (a menos que seja uma tabela derivada; nesse caso, você não pode usar essa dica específica)

user52212
fonte
1
O SQL Server 2005 adicionou "versionamento de linha", o que deve reduzir bastante a necessidade de nolocks. Atualizamos recentemente e não estamos treinando nossos DBAs para que parem de usá-los.
27139 Jonathan Allen
5

A resposta mais simples é uma pergunta simples - você precisa que seus resultados sejam repetíveis? Se sim, o NOLOCKS não é apropriado em nenhuma circunstância

Se você não precisar de repetibilidade, os nolocks poderão ser úteis, especialmente se você não tiver controle sobre todos os processos que se conectam ao banco de dados de destino.

Ed Green
fonte