Por que usar um nível de isolamento READ UNCOMMITTED?

225

Em inglês simples, quais são as desvantagens e vantagens de usar

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

em uma consulta para aplicativos .NET e aplicativos de serviços de relatório?

Kip Real
fonte

Respostas:

210

Esse nível de isolamento permite leituras sujas. Uma transação pode ver alterações não confirmadas feitas por outra transação.

Para manter o nível mais alto de isolamento, um DBMS geralmente adquire bloqueios nos dados, o que pode resultar em perda de simultaneidade e uma alta sobrecarga de bloqueio. Esse nível de isolamento relaxa essa propriedade.

Você pode conferir o artigoREAD UNCOMMITTED da Wikipedia sobre alguns exemplos e leituras adicionais.


Você também pode estar interessado em conferir o artigo do blog de Jeff Atwood sobre como ele e sua equipe resolveram um problema de impasse nos primeiros dias do Stack Overflow. De acordo com Jeff:

Mas é nolockperigoso? Você pode acabar lendo dados inválidos com read uncommittedativado? Sim, em teoria. Você não encontrará escassez de astronautas de arquitetura de banco de dados que começam a lançar a ciência do ACID em você e quase acionam o alarme de incêndio do prédio quando você diz que deseja tentar nolock. É verdade: a teoria é assustadora. Mas eis o que penso: "Na teoria, não há diferença entre teoria e prática. Na prática, existe".

Eu nunca recomendaria usar nolock como uma correção geral "boa para o que lhe aflige" o óleo de cobra para qualquer problema de impasse no banco de dados que você possa ter. Você deve tentar diagnosticar a origem do problema primeiro.

Mas, na prática, adicionar nolockperguntas que você absolutamente conhece como assuntos simples e diretos de leitura nunca parece levar a problemas ... Desde que você saiba o que está fazendo.

Uma alternativa para o READ UNCOMMITTEDnível que você pode querer considerar é o READ COMMITTED SNAPSHOT. Citando Jeff novamente:

Os snapshots contam com um método de rastreamento de alterações de dados totalmente novo ... mais do que apenas uma pequena alteração lógica, exige que o servidor lide com os dados fisicamente de maneira diferente. Quando esse novo método de rastreamento de alterações de dados é ativado, ele cria uma cópia ou instantâneo de cada alteração de dados. Ao ler essas capturas instantâneas em vez de dados ativos em momentos de contenção, os bloqueios compartilhados não são mais necessários nas leituras e o desempenho geral do banco de dados pode aumentar.

Daniel Vassallo
fonte
13
O autor parece sugerir que a leitura não confirmada / sem bloqueio retornará os dados que foram confirmados pela última vez. Meu entendimento é de que a leitura não confirmada retornará qualquer valor definido pela última vez, mesmo em transações não confirmadas. Nesse caso, o resultado não seria recuperar dados "alguns segundos desatualizados". Seria (ou pelo menos poderia, se a transação que gravou os dados que você lê fosse revertida) estivesse recuperando dados que não existem ou nunca foram confirmados. Estou enganado?
Xr280xr
4
Ótima resposta. BTW, a Oracle tem "instantâneo" por padrão desde que eu o conheço, provavelmente décadas antes do Sql Server introduzi-lo. Fiquei bastante decepcionado ao iniciar o SQL Server e descobri que todos os problemas de simultaneidade foram resolvidos usando mecanismos de bloqueio "primitivos". Nunca vi "Leitura não confirmada" no Oracle. E o praticante é tão feliz quanto os astronautas.
Stefan Steinegger 10/10
13
READ UNCOMMITTEDtambém pode fazer com que você leia linhas duas vezes ou perca linhas inteiras . Se uma divisão de página ocorrer enquanto você estiver lendo, poderá perder partes inteiras de dados. WITH(NOLOCK)só deve ser usado se a precisão dos resultados não é importante
Ian Boyd
8
@DanielNolan, Recomendar o artigo é perigoso porque Jeff não sabia o que estava fazendo . A leitura não solicitada apenas faz sentido, pois a leitura de dados nunca será modificada. Tentar usar isso para ler tabelas que seriam gravadas significa que , na prática, você lerá algo que será revertido. Não é apenas a leitura de dados com alguns segundos, mas você .................................. ................... ‌ ‌ ........................... ...
Pacerier 19/12/14
5
................................... estão lendo dados que nunca são confirmados. Essa é a própria definição de leituras corrompidas. E se você escrever com base nos resultados dessas leituras não confirmadas, na prática estará gravando dados corrompidos. O artigo também afirmava que "o MySQL, que cresceu em aplicativos da Web, é muito menos pessimista do que o SQL Server". Não é verdade, o Sql Server trabalha no nível de confirmação de leitura por padrão, enquanto o MySQL trabalha em leituras repetíveis por padrão, a cinco níveis de leitura não confirmada.
Pacerier
36

Isso pode ser útil para ver o progresso de consultas longas de inserção, fazer estimativas aproximadas (semelhantes COUNT(*)ou aproximadas SUM(*)) etc.

Em outras palavras, os resultados retornados pelas consultas de leitura suja são bons, desde que você os trate como estimativas e não tome nenhuma decisão crítica com base neles.

Quassnoi
fonte
36

Meu caso de uso favorito para read uncommited é depurar algo que está acontecendo dentro de uma transação.

Inicie seu software em um depurador, enquanto você percorre as linhas de código, ele abre uma transação e modifica seu banco de dados. Enquanto o código está parado, você pode abrir um analisador de consultas, definido no nível de isolamento não lido de leitura e fazer consultas para ver o que está acontecendo.

Você também pode usá-lo para verificar se os procedimentos de execução longa estão paralisados ​​ou atualizando corretamente seu banco de dados.

É ótimo se sua empresa adora fazer procedimentos armazenados excessivamente complexos.

Neves
fonte
6
Minha empresa adora fazer procedimentos armazenados excessivamente complexos. Que ótima idéia para solução de problemas!
Brandon
22

A vantagem é que pode ser mais rápido em algumas situações. A desvantagem é que o resultado pode estar errado (dados que ainda não foram confirmados podem ser retornados) e não há garantia de que o resultado seja repetível.

Se você se preocupa com a precisão, não use isso.

Mais informações estão no MSDN :

Implementa leitura suja ou bloqueio de nível de isolamento 0, o que significa que nenhum bloqueio compartilhado é emitido e nenhum bloqueio exclusivo é respeitado. Quando esta opção está definida, é possível ler dados não confirmados ou sujos; os valores nos dados podem ser alterados e as linhas podem aparecer ou desaparecer no conjunto de dados antes do final da transação. Esta opção tem o mesmo efeito que definir NOLOCK em todas as tabelas em todas as instruções SELECT em uma transação. Este é o menos restritivo dos quatro níveis de isolamento.

Mark Byers
fonte
Como isso afetaria a velocidade da consulta?
Kip Real
11
As selectinstruções @Kip - não precisariam esperar para adquirir bloqueios compartilhados em recursos que são bloqueados exclusivamente por outras transações.
Jarrod Dixon
15

Quando está tudo bem em usar READ UNCOMMITTED?

Regra prática

Bom : grandes relatórios agregados mostrando totais em constante mudança.

Arriscado : Quase todo o resto.

A boa notícia é que a maioria dos relatórios somente leitura se enquadra nessa categoria de Bom .

Mais detalhes...

Ok para usá-lo:

  • Quase todos os relatórios agregados voltados ao usuário para dados atuais e não estáticos, por exemplo, vendas acumuladas no ano. Ela corre o risco de uma margem de erro (talvez <0,1%), que é muito menor do que outros fatores de incerteza, como erro de entrada ou apenas a aleatoriedade de quando exatamente os dados são registrados minuto a minuto.

Isso cobre provavelmente a maioria do que um departamento de Business Intelligence faria no, digamos, SSRS. A exceção, é claro, é qualquer coisa com sinais de $ na frente. Muitas pessoas respondem por dinheiro com muito mais zelo do que as aplicadas nas principais métricas relacionadas necessárias para atender o cliente e gerar esse dinheiro. (Eu culpo os contadores).

Quando arriscado

  • Qualquer relatório que desça para o nível de detalhe. Se esse detalhe for necessário, geralmente implica que cada linha será relevante para uma decisão. De fato, se você não pode extrair um pequeno subconjunto sem bloqueá-lo, talvez seja pelo bom motivo que ele está sendo editado no momento.

  • Data histórica. Raramente faz uma diferença prática, mas, embora os usuários entendam que dados em constante mudança não podem ser perfeitos, eles não sentem o mesmo sobre dados estáticos. Leituras sujas não vão doer aqui, mas leituras duplas podem ocasionalmente ser. Vendo que você não deveria ter bloqueios em dados estáticos, por que arriscar?

  • Quase tudo o que alimenta um aplicativo que também possui recursos de gravação.

Quando mesmo o cenário OK não está bom.

  • Existem aplicativos ou processos de atualização fazendo uso de grandes transações únicas? Os que são removidos e depois reinseridos muitos registros nos quais você está relatando? Nesse caso, você realmente não pode usar NOLOCKessas tabelas para nada.
Adamantish
fonte
Bom ponto sobre os relatórios. Na verdade, a primeira ideia que me veio à mente foi se eu deveria usar read uncommittedpara aplicativos da Web quando o usuário vê alguma grade da interface do usuário em que a precisão dos dados não é tão importante. O usuário só quer uma rápida visão geral de quais registros podem estar lá, e talvez com alguma paginação, classificação e filtragem. Somente quando o usuário clica no botão Editar, tento ler o registro mais atual com um nível de isolamento mais rigoroso. Essa abordagem não deveria ser melhor em termos de desempenho?
JustAMartin
Sim, acho isso razoável. Lembre-se de que o problema mais significativo é garantir que os dados não tenham sido alterados por outra pessoa entre o momento em que você clica no botão de edição e o momento do envio. Você pode lidar com isso iniciando uma transação buscando os dados como select item from things with (UPDLOCK). Coloque um tempo limite rápido lá para que, se não conseguir obter o bloqueio rapidamente, informe ao usuário que está sendo editado. Isso o manterá seguro não apenas dos usuários, mas dos desenvolvedores. O único problema aqui é que você deve começar a pensar em intervalos e em como lidar com isso na interface do usuário.
Adamantish
6

Em relação aos relatórios, usamos em todas as nossas consultas de relatórios para impedir que uma consulta atinja os bancos de dados. Podemos fazer isso porque estamos obtendo dados históricos, não dados de até microssegundos.

Hugh Seagraves
fonte
4

Use READ_UNCOMMITTED em situações em que é improvável que a origem seja alterada.

  • Ao ler dados históricos. por exemplo, alguns logs de implantação que ocorreram dois dias atrás.
  • Ao ler os metadados novamente. por exemplo, aplicativo baseado em metadados.

Não use READ_UNCOMMITTED quando souber que a fonte pode mudar durante a operação de busca.

neo
fonte
1
Sinto que o contrário se aplica. Em primeiro lugar, os dados estáticos devem ser lidos bem, sem blocos. Se ele não bloquear então você agora descoberto há um importante problema de transação pendurado para correção. Os usuários também esperam que isso corresponda à última casa decimal, independentemente do que imprimir para o relatório anual do ano passado. Geralmente, eles não esperam o mesmo dos relatórios que sabem que estão em constante fluxo. Isso não vale para relatórios financeiros detalhados, extremamente sensíveis ao tempo, mas se 1 erro de entrada em 1000 é tolerável, o mesmo ocorre READ UNCOMMITTED.
Adamantish
TLDR: se os dados não forem alterados, você não precisará de LER NÃO COMPROMETIDO, porque não há blocos de qualquer maneira. Se você está errado e isso muda, é bom impedir que os usuários obtenham dados mais sujos do que o esperado.
Adamantish
Sim, costumo concordar com a @Adamantish aqui - você pode se beneficiar da READ UNCOMMITTEDmaioria das situações em que seus dados estão sendo usados ​​ativamente e você deseja reduzir a carga no servidor para evitar possíveis bloqueios e reversões de transações apenas porque alguns usuários abusam sem cuidado " Atualizar "em uma página da web com uma grade de dados. Os usuários que visualizam vários registros ao mesmo tempo geralmente não se importam muito se os dados estiverem um pouco desatualizados ou parcialmente atualizados. Somente quando um usuário estiver prestes a editar um registro, você poderá fornecer os dados mais precisos.
JustAMartin
2

Isso fornecerá leituras sujas e mostrará transações que ainda não foram confirmadas. Essa é a resposta mais óbvia. Não acho que seja uma boa ideia usar isso apenas para acelerar suas leituras. Existem outras maneiras de fazer isso se você usar um bom design de banco de dados.

Também é interessante observar o que não está acontecendo. READ UNCOMMITTED não ignora apenas outros bloqueios de tabela. Também não está causando bloqueios por conta própria.

Considere que você está gerando um relatório grande ou está migrando dados do seu banco de dados usando uma instrução SELECT grande e possivelmente complexa. Isso fará com que um bloqueio compartilhado possa ser escalado para um bloqueio de tabela compartilhado durante a transação. Outras transações podem ser lidas na tabela, mas as atualizações são impossíveis. Pode ser uma má idéia se for um banco de dados de produção, pois a produção pode parar completamente.

Se você estiver usando READ UNCOMMITTED, não definirá um bloqueio compartilhado na tabela. Você pode obter o resultado de algumas novas transações ou pode não depender de onde foram inseridos os dados e por quanto tempo a transação SELECT foi lida. Você também pode obter os mesmos dados duas vezes se, por exemplo, ocorrer uma divisão de página (os dados serão copiados para outro local no arquivo de dados).

Portanto, se for muito importante para você que os dados possam ser inseridos enquanto você faz o SELECT, READ UNCOMMITTED pode fazer sentido. Você deve considerar que seu relatório pode conter alguns erros, mas se for baseado em milhões de linhas e apenas algumas delas forem atualizadas ao selecionar o resultado, isso pode ser "bom o suficiente". Sua transação também pode falhar por completo, pois a exclusividade de uma linha pode não ser garantida.

Uma maneira melhor pode ser usar o SNAPSHOT ISOLATION LEVEL, mas seus aplicativos podem precisar de alguns ajustes para usá-lo. Um exemplo disso é se seu aplicativo usa um bloqueio exclusivo em uma linha para impedir que outros o leiam e entrem no modo de edição na interface do usuário. O NÍVEL DE ISOLAMENTO DO INSTANTÂNEO também possui uma penalidade de desempenho considerável (especialmente no disco). Mas você pode superar isso jogando o hardware no problema. :)

Você também pode considerar restaurar um backup do banco de dados para relatar ou carregar dados em um data warehouse.

Olle Johansson
fonte
0

Ele pode ser usado para uma tabela simples, por exemplo, em uma tabela de auditoria somente inserção, onde não há atualização para a linha existente e nenhum fk para outra tabela. A inserção é uma inserção simples, com pouca ou nenhuma chance de reversão.

Sofian
fonte
-7

Eu sempre uso LER SEM COMPROMISSO agora. É rápido com o mínimo de problemas. Ao usar outros isolamentos, você quase sempre encontrará alguns problemas de bloqueio.

Contanto que você use os campos de incremento automático e preste um pouco mais de atenção às inserções do que a sua multa, e poderá dizer adeus aos problemas de bloqueio.

Você pode cometer erros com READ UNCOMMITED, mas, para ser sincero, é muito fácil garantir que suas inserções sejam a prova completa. Inserções / atualizações que usam os resultados de uma seleção são as únicas coisas a serem observadas. (Use READ COMMITTED aqui ou garanta que leituras sujas não causem problemas)

Então vá para Dirty Reads (Especialmente para grandes relatórios), seu software será mais suave ...

Clive
fonte
6
Isso é muito impreciso e apenas toca a superfície dos problemas que podem ocorrer com o nolock. As páginas podem ser divididas, as junções podem falhar, você pode ler dados inexistentes ou duplicar dados. Não há como fazê-lo à prova de falhas: você não pode confiar na precisão de nada neste nível de isolamento. READ COMMITTED SNAPSHOT é um menos perigoso "panacéia fake"
Mark Sowul
@ MarkSowul O voto negativo desta resposta me parece injusto. O @Clive deixou claro que ele mudaria Committedpara inserções e atualizações. Quanto a outros problemas, ele também demonstrou conhecimento dos problemas de divisão de página ao mencionar o uso de uma chave de incremento automático. Concordo com ele que quase todas as reportagens ao vivo feitas para serem lidas por apenas um ser humano podem tolerar pequenas discrepâncias na casa decimal final. Eu concordo que é uma história diferente para listagens detalhadas ou dados destinados a serem lidos e transformados automaticamente, assim como Clive.
Adamantish
1
Este comentário também demonstra uma falta de entendimento completo dos possíveis problemas que acompanham o nolock. "Pequenas discrepâncias na casa decimal final" dificilmente o cobrem. Mesmo tocar no "apenas usar a leitura confirmada para inserções / atualizações" está errado como orientação geral (e se for "inserir um registro se não existir"?). De qualquer forma, "[ler não confirmado] é rápido com o mínimo de problemas" está categoricamente errado.
Mark Sowul
Para constar, concordo com sua resposta, Adamantish: agregações aproximadamente precisas e pouco mais.
Mark Sowul