A má prática do NOLOCK (Sql Server dica)?


125

Estou no negócio de criar sites e aplicativos que não são de missão crítica -> por exemplo. software bancário, voo espacial, aplicativo de monitoramento de terapia intensiva etc. Você entendeu a idéia.

Então, com esse enorme aviso, é ruim usar a dica NOLOCK em alguma instrução SQL? Alguns anos atrás, foi sugerido por um colega Administrador Sql que eu deveria usar o NOLOCK se estiver satisfeito com uma "leitura suja", o que me proporcionará um pouco mais de desempenho do meu sistema, pois cada leitura não bloqueia o mesa / linha / o que for.

Também me disseram que é uma ótima solução se eu estiver enfrentando impasses. Então, comecei a seguir esse pensamento por alguns anos até que um guru do Sql estivesse me ajudando com algum código aleatório e notei todos os NOLOCKS no meu código sql. Eu fui educadamente repreendido e ele tentou me explicar (por que não é uma coisa boa) e eu meio que me perdi. Eu senti que a essência da explicação dele era 'é uma solução de band-aid para um problema mais sério .. especialmente se você estiver enfrentando um impasse. Como tal, corrija a raiz do problema '.

Recentemente, pesquisei no Google e me deparei com este post .

Então, alguns sql db guru sensei podem me esclarecer?


Não entendo Sam, você está dizendo para usar o isolamento de instantâneo se for um site de leitura pesada. Mas então você está dizendo que SO fez isso, e é ruim? ou apenas o uso de NOLOCK?
Pure.Krome

Respostas:


67

Com a dica NOLOCK, o nível de isolamento da transação para a SELECTinstrução é READ UNCOMMITTED. Isso significa que a consulta pode ver dados sujos e inconsistentes.

Não é uma boa ideia aplicar-se como regra. Mesmo que esse comportamento de leitura suja seja bom para o seu aplicativo baseado na Web de missão crítica, uma verificação NOLOCK pode causar um erro 601 que encerrará a consulta devido à movimentação de dados como resultado da falta de proteção de bloqueio.

Sugiro a leitura de Quando o isolamento de instantâneo ajuda e quando dói - o MSDN recomenda o uso do INSTANTÂNEO LIDO COMPRIDO, em vez do INSTANTÂNEO, na maioria das circunstâncias.


1
Rex, sinta-se à vontade para adicionar uma observação sobre o isolamento de instantâneo.
Sam Saffron

2
Sim, Sam está dizendo isolamento de instantâneo e você está sugerindo Leia instantâneo comprometido. Estou ficando tão confuso: P (e eu tenho ainda para aprofundar os artigos, também!)
Pure.Krome

2
É ocasionalmente útil, mas não normalmente para produção. Eu o uso frequentemente para extrair uma amostra de dados para testar ou gerar relatórios, nos quais me preocupo principalmente com a ordem aproximada de magnitude em que uma leitura suja não importa.
TimothyAWiseman

NOLOCK == Eu não ligo se linhas comprometidas são perdidas, linhas não confirmadas são incluídas, em casos raros, a mesma linha é retornada mais de uma vez e, em casos muito raros, são retornadas linhas que não correspondem à minha consulta. (Vejo blogs.msdn.com/b/sqlcat/archive/2007/02/01/... , encontrados a partir de outro Q'n SO sobre este tema)
Andrew Hill

106

Antes de trabalhar no Stack Overflow, eu era contra NOLOCKno princípio de que você poderia executar uma SELECTcom NOLOCKe voltar resultados com os dados que podem estar fora de data ou inconsistente. Um fator a se pensar é quantos registros podem ser inseridos / atualizados ao mesmo tempo em que outro processo pode estar selecionando dados da mesma tabela. Se isso acontecer muito, há uma alta probabilidade de conflitos, a menos que você use um modo de banco de dados como READ COMMITED SNAPSHOT.

Desde então, mudei de perspectiva sobre o uso de NOLOCKdepois de testemunhar como ele pode melhorar o SELECTdesempenho e eliminar os impasses em um SQL Server carregado em massa. Há momentos em que você pode não se importar se seus dados não são exatamente 100% confirmados e você precisa de resultados rapidamente, mesmo que estejam desatualizados.

Faça uma pergunta a si mesmo ao pensar em usar NOLOCK:

Minha consulta inclui uma tabela que possui um número alto de comandos INSERT/ UPDATEe me importo se os dados retornados de uma consulta podem estar faltando essas alterações em um determinado momento?

Se a resposta for não, use NOLOCKpara melhorar o desempenho.


Acabei de realizar uma pesquisa rápida pelo NOLOCK palavra chave na base de código do Stack Overflow e encontrei 138 instâncias, por isso a usamos em alguns lugares.


7
IMO, isso é um pouco simplista. Os deadlocks podem ser removidos usando índices de cobertura, diminuindo a pressão do índice de cluster.
12511 Mitch

8
Não desejo diminuir a importância de uma boa cobertura de índices. Às vezes, as consultas usando o NOLOCK podem adicionar desempenho adicional aos ganhos obtidos pelos índices em tabelas com um número alto de inserções / atualizações. A velocidade da consulta no estouro de pilha é primordial, mesmo ao custo de dados inexatos ou ausentes.
Geoff Dalgas

9
Aparentemente, pode-se obter linhas duplicadas usando NOLOCK. Isso significa que eu tenho que rebaixar sua resposta. Desculpe.
ErikE

1
@MitchWheat A SELECT, a leitura somente de um índice de cobertura, pode causar um conflito. SPID 1) inicia um a SELECTpartir do índice de cobertura. SPID 2) Inicie uma UPDATEtabela. A atualização passa para a atualização do índice de cobertura. UPDATEatinge um intervalo de índice bloqueado pelo SELECTe fica bloqueado. O SPID 1) ainda procura pelo índice de cobertura, encontra um intervalo bloqueado pelo UPDATEe fica bloqueado. PRAZO . Nada pode resolver esse impasse (exceto captura de erro SQL Server 1205, e automaticamente tentar novamente, ou usando NOLOCK)
Ian Boyd

2
Penso que o importante a notar sobre esta resposta é que ela era apropriada para o problema em questão . Dependendo do seu aplicativo, o risco de dados obsoletos / não confirmados / duplicados / ausentes pode não valer a pena.
Holistic Developer

20

Se você não se importa com leituras sujas (ou seja, em uma situação predominantemente READ), tudo NOLOCKbem.

MAS , lembre-se de que a maioria dos problemas de bloqueio ocorre devido à falta de índices 'corretos' para sua carga de trabalho de consulta (supondo que o hardware esteja pronto para a tarefa).

E a explicação do guru estava correta. Geralmente é uma solução de band-aid para um problema mais sério.

Edit : Definitivamente, não estou sugerindo que o NOLOCK deva ser usado. Acho que deveria ter deixado isso obviamente claro. (Eu só o usaria em circunstâncias extremas em que havia analisado que estava tudo bem). Como exemplo, um tempo atrás, trabalhei em alguns TSQL que foram polvilhados com o NOLOCK para tentar aliviar os problemas de bloqueio. Removai todos eles, implementei os índices corretos e TODOS os impasses desapareceram.


3
Hmm .. ainda não entendi. Então está tudo bem, mas também está em má forma .. é isso que você está dizendo?
Pure.Krome

Supondo que você NUNCA se importe com leituras sujas, isso não fará mal. Mas geralmente é um caso de tratar o sintoma e não a causa ...
Mitch Wheat

2
Bem, eu não acho que o seu justo rexem foi apenas votado, acho que você não resolveu os erros arbitrários que apenas flutuam quando você usa o nolock. Não é bom obter uma página de erro em branco de vez em quando no seu site, é uma forma muito ruim. Eu não gosto da afirmação de que "se você não se importam sobre sujo lê o seu bem" ... não é bom, mesmo se você não se preocupam com leituras sujas
Sam Saffron

A página em branco exibida quando uma consulta gera uma exceção para a qual você não implementou a lógica de repetição. O que acontece nos seus sites quando a execução da consulta resulta com uma exceção? Você tem uma nova lógica em todos os lugares?
Sam Saffron

Faça uma consulta muito bem otimizada que você sabe que está atingindo índices adequados. Em seguida, adicione dicas nolock e observe-o ficar mais rápido. Se você não se importa com leituras sujas, nunca se machucará usando o nolock.
Hardwareguy

13

Duvido que fosse um "guru" que tivesse alguma experiência em tráfego intenso ...

Os sites geralmente estão "sujos" quando a pessoa está visualizando a página completamente carregada. Considere um formulário que carrega do banco de dados e salva os dados editados? É idiota a maneira como as pessoas falam sobre leituras sujas sendo tão não-não.

Dito isto, se você tiver várias camadas construídas em suas seleções, poderá criar uma redundância perigosa. Se você estiver lidando com cenários financeiros ou de status, precisará não apenas de leitura / gravação de dados transacionais, mas também de uma solução de concorrência adequada (algo que a maioria dos "gurus" não se incomoda).

Por outro lado, se você tem uma pesquisa avançada de produtos para um site (ou seja, algo que provavelmente não será armazenado em cache e é um pouco intensivo) e você já construiu um site com mais de alguns usuários simultâneos (fenomenal quantos "especialistas" não têm), é ridículo engarrafar todos os outros processos por trás dele.

Saiba o que isso significa e use-o quando apropriado. Atualmente, seu banco de dados quase sempre será o principal gargalo da sua garrafa, e ser inteligente sobre o uso do NOLOCK pode economizar milhares em infraestrutura.

EDIT: Não são apenas os impasses que ajudam, é também o quanto você fará todo mundo esperar até terminar, ou vice-versa.

Usando a dica NOLOCK no EF4?


10

Nenhuma das respostas está errada, por mais confuso que seja.

  • Ao consultar valores / linhas únicos, é sempre uma prática ruim usar o NOLOCK - você provavelmente nunca deseja exibir informações incorretas ou talvez executar alguma ação com dados incorretos.
  • Ao exibir informações estatísticas aproximadas, o NOLOCK pode ser muito útil. Tome SO como um exemplo: seria absurdo usar bloqueios para ler o número exato de visualizações de uma pergunta ou o número exato de perguntas para uma tag. Ninguém se importa se você indicar incorretamente 3360 perguntas marcadas com "sql-server" agora e, devido a uma reversão de transação, 3359 perguntas um segundo depois.

Não concordo com o seu primeiro ponto. SE você está consultando valores / linhas únicos e está especificando um ID exclusivo para essa linha e sabe que nenhum outro processo o acessará, usar o nolock é perfeitamente aceitável e reduz o bloqueio em um aplicativo simultâneo.
tuseau 16/05

1
Não, não é. A linha pode mudar por outros motivos, por exemplo, a inserção de outra linha divide a página. Indexação adequada, leitura instantânea confirmada e isolamento de captura instantânea são quase sempre melhores idéias.
precisa saber é o seguinte

1
@tuseau se "sabe" que nenhum outro processo será acessar a linha, o ato de tomar um bloqueio não vai bloquear qualquer coisa, por isso custa-lhe (quase) nada,
Andrew Hill

2

Como desenvolvedor profissional, eu diria que depende. Mas eu definitivamente sigo os conselhos dos GATS e OMG Ponies. Saiba o que você está fazendo, saiba quando ajuda e quando dói e

leia dicas e outras idéias ruins

o que pode fazer você entender o servidor sql mais profundamente. Geralmente, sigo a regra de que as dicas do SQL são MAL, mas, infelizmente, eu as uso de vez em quando quando estou cansado de forçar o SQL Server a fazer coisas ... Mas esses são casos raros.

Lucas


2

Quando o suporte ao aplicativo queria responder a consultas ad-hock do servidor de produção usando SSMS (que não eram atendidos por meio de relatórios), solicitei que eles usassem o nolock. Dessa forma, o negócio 'principal' não é afetado.


2

Concordo com alguns comentários sobre a dica do NOLOCK e, especialmente, com aqueles que dizem "use-a quando for apropriado". Se o aplicativo tiver sido mal escrito e estiver usando uma maneira inadequada de simultaneidade - isso pode causar o aumento do bloqueio. A tabela altamente transacional também fica bloqueada o tempo todo devido à sua natureza. Ter uma boa cobertura de índice não ajudará na recuperação dos dados, mas configurar ISOLATION LEVEL como READ UNCOMMITTED. Também acredito que o uso da dica NOLOCK é seguro em muitos casos quando a natureza das alterações é previsível. Por exemplo - na fabricação quando trabalhos com viajantes estão passando por processos diferentes com muitas inserções de medidas, é possível executar com segurança consultas no trabalho final com a dica NOLOCK e, dessa forma, evitar colisão com outras sessões que colocam bloqueios PROMOTED ou EXCLUSIVO na mesa /página. Os dados que você acessa nesse caso são estáticos, mas podem residir em uma tabela muito transacional com centenas de milhões de registros e milhares de atualizações / inserções por minuto. Felicidades


2

Acredito que praticamente nunca é correto usar o nolock.

Se você estiver lendo uma única linha, o índice correto significa que você não precisará do NOLOCK, pois as ações individuais da linha são concluídas rapidamente.

Se você estiver lendo muitas linhas para algo que não seja exibição temporária e se preocupa em poder repetir o resultado ou defender pelo número produzido, o NOLOCK não é apropriado.

NOLOCK é uma marca substituta para "não me importo se esta resposta contiver linhas duplicadas, linhas excluídas ou linhas que nunca foram inseridas para começar por causa da reversão"

Erros possíveis sob NOLOCK:

  • Linhas que correspondem não são retornadas.
  • linhas únicas são retornadas várias vezes (incluindo várias instâncias da mesma chave primária)
  • Linhas que não correspondem são retornadas.

Qualquer ação que possa causar uma divisão de página enquanto a seleção noLock estiver em execução pode causar essas coisas. Quase qualquer ação (mesmo uma exclusão) pode causar uma divisão de página.

Portanto: se você "sabe" que a linha não será alterada enquanto estiver em execução, não use nolock, pois um índice permitirá uma recuperação eficiente.

Se você suspeitar que a linha pode mudar enquanto a consulta está em execução e se preocupa com a precisão, não use nolock.

Se você estiver considerando NOLOCK por causa de conflitos, examine a estrutura do plano de consulta para verificações inesperadas da tabela, rastreie os conflitos e veja por que eles ocorrem. NOLOCK em torno de gravações pode significar que as consultas que antes estavam em um impasse potencialmente escreveriam a resposta errada.


2

As melhores soluções, quando possível, são:

  • Replicar seus dados (usando a replicação de log) em um banco de dados de relatórios.
  • Use instantâneos da SAN e monte uma versão consistente do banco de dados
  • Use um banco de dados que tenha um melhor nível de isolamento de transação fundamental

O nível de isolamento de transação INSTANTÂNEO foi criado porque a MS estava perdendo vendas para a Oracle. O Oracle usa desfazer / refazer logs para evitar esse problema. O Postgres usa MVCC. No futuro, o Heckaton da MS usará o MVCC, mas faltam anos para estar pronto para a produção.


Há um erro de digitação acima. Quero dizer "melhor mecanismo fundamental de isolamento de transações".
PWY

1
INSTANTÂNEO O nível de isolamento de transação é uma invenção da MS. Basicamente, ele coloca os dados em uma tabela temporária no TEMPDB. Esse banco de dados é compartilhado entre todos os bancos de dados na caixa. Portanto, convém usar SSDs para TEMPDB quando possível. Provavelmente isso é menos esforço do que as outras opções.
pwy

1

O NOLOCK é frequentemente explorado como uma maneira mágica de acelerar as leituras do banco de dados, mas tento evitar usá-lo sempre que possível.

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

Um erro ou conjunto de resultados pode estar vazio, estar faltando linhas ou exibir a mesma linha várias vezes.

Isso ocorre porque outras transações estão movendo dados ao mesmo tempo em que você os lê.

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.


-2

Na vida real, onde você encontra sistemas já escritos e adiciona índices a tabelas e depois diminui drasticamente o carregamento de dados de uma tabela de dados 14gig, às vezes você é forçado a usar o WITH NOLOCK em seus relatórios e a análise de final de mês para que as funções agregadas (soma , contagem, etc.) não fazem linha, página, bloqueio de tabela e impedem o desempenho geral. É fácil dizer que em um novo sistema nunca use WITH NOLOCK e use índices - mas a adição de índices reduz severamente o carregamento de dados e, quando me dizem isso, altere a base de código para excluir índices, depois carregue em massa e recrie os índices - o que está tudo muito bem, se você estiver desenvolvendo um novo sistema. Mas não quando você já possui um sistema.


1
o que está dizendo
Max Alexander Hanna
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.