Perché usare un livello di isolamento READ UNOMOMITTED?


225

In parole povere, quali sono gli svantaggi e i vantaggi dell'utilizzo

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

in una query per applicazioni .NET e applicazioni di servizi di reportistica?

Risposte:


210

Questo livello di isolamento consente letture sporche. Una transazione può vedere le modifiche non confermate apportate da un'altra transazione.

Per mantenere il massimo livello di isolamento, un DBMS di solito acquisisce blocchi sui dati, il che può comportare una perdita di concorrenza e un elevato sovraccarico di blocco. Questo livello di isolamento rilassa questa proprietà.

Potresti voler leggere l' articolo di WikipediaREAD UNCOMMITTED per alcuni esempi e ulteriori letture.


Potresti anche essere interessato a leggere l' articolo del blog di Jeff Atwood su come lui e il suo team hanno affrontato un problema di deadlock nei primi giorni di Stack Overflow. Secondo Jeff:

Ma è nolockpericoloso? Potresti finire con la lettura di dati non validi con read uncommittedon? Sì, in teoria. Non mancheranno gli astronauti dell'architettura del database che iniziano a far cadere la scienza ACID su di te e tutti ma tirano l'allarme antincendio dell'edificio quando dici loro che vuoi provare nolock. È vero: la teoria fa paura. Ma ecco cosa penso: "In teoria non c'è differenza tra teoria e pratica. In pratica c'è".

Non consiglierei mai di utilizzare nolock come soluzione generale "buono per ciò che ti affligge" l'olio di serpente per eventuali problemi di deadlock del database che potresti avere. Dovresti prima provare a diagnosticare l'origine del problema.

Ma in pratica l'aggiunta nolocka domande che conosci assolutamente sono affari di sola lettura semplici che non sembrano mai portare a problemi ... Finché sai cosa stai facendo.

Un'alternativa al READ UNCOMMITTEDlivello che potresti voler prendere in considerazione è la READ COMMITTED SNAPSHOT. Citando di nuovo Jeff:

Le istantanee si basano su un metodo di tracciamento delle modifiche dei dati completamente nuovo ... più che una leggera modifica logica, richiede al server di gestire i dati fisicamente in modo diverso. Una volta abilitato questo nuovo metodo di tracciamento della modifica dei dati, crea una copia o un'istantanea di ogni modifica dei dati. Leggendo queste istantanee anziché i dati in tempo reale durante i conflitti, i blocchi condivisi non sono più necessari nelle letture e le prestazioni complessive del database potrebbero aumentare.


13
L'autore sembra sottintendere che la lettura senza commit / nessun blocco restituirà qualsiasi dato sia stato impegnato l'ultima volta. La mia comprensione viene letta non impegnata restituirà qualsiasi valore impostato l'ultima volta anche da transazioni non impegnate. In tal caso, il risultato non sarebbe recuperare i dati "pochi secondi non aggiornati". (O almeno potrebbe se il rollback della transazione che ha scritto i dati letti) sta recuperando dati che non esistono o che non sono mai stati sottoposti a commit. Mi sbaglio?
xr280xr,

4
Bella risposta. A proposito, Oracle ha "snapshot" per impostazione predefinita da quando lo conosco, probabilmente decenni prima che Sql Server lo introducesse. Sono rimasto piuttosto deluso quando ho iniziato con SQL Server e ho scoperto che tutti i problemi di concorrenza sono stati risolti utilizzando meccanismi di blocco "primitivi". Non ho mai visto "Leggi senza commit" in Oracle. E il praticante è felice come gli astronauti.
Stefan Steinegger,

13
READ UNCOMMITTEDpuò anche farti leggere le righe due volte o perdere intere righe . Se durante la lettura si verifica una divisione della pagina, puoi perdere interi blocchi di dati. WITH(NOLOCK)dovrebbe essere usato solo se la precisione dei risultati non è importante
Ian Boyd,

8
@DanielNolan, Raccomandare che l'articolo sia pericoloso perché Jeff non sapeva cosa stesse facendo . La lettura senza decompressione ha senso solo per la lettura dei dati che non verrà mai modificata. Cercare di usarlo per leggere le tabelle su cui verrebbe scritto significa che in pratica leggerai qualcosa che viene eseguito il rollback. Non si tratta solo di leggere dati vecchi di pochi secondi, ma di .................................. ................... ........................... ....
Pacerier,

5
................................... stanno leggendo dati che non si impegnano nemmeno. Questa è la definizione stessa di letture corrotte. E se hai intenzione di scrivere in base ai risultati di quelle letture non impegnate, in pratica scriverai dati danneggiati. Inoltre l'articolo affermava che "MySQL, che è cresciuto su app Web, è molto meno pessimista di SQL Server". Non è vero, Sql Server funziona a livello di commit per impostazione predefinita, mentre MySQL funziona a lettura ripetibile per impostazione predefinita, a cinque livelli di distanza dalla lettura senza commit.
Pacerier,

36

Questo può essere utile per vedere lo stato di avanzamento delle query di inserimento lungo, fare stime approssimative (simili COUNT(*)o approssimative SUM(*)) ecc.

In altre parole, i risultati restituiti dalle query di lettura sporche vanno bene purché le trattiate come stime e non prendiate decisioni critiche basate su di esse.


36

Il mio caso d'uso preferito read uncommitedè il debug di qualcosa che sta accadendo all'interno di una transazione.

Avviare il software con un debugger, mentre si passa attraverso le righe di codice, apre una transazione e modifica il database. Mentre il codice viene arrestato, è possibile aprire un analizzatore di query, impostare il livello di isolamento non letto letto ed eseguire query per vedere cosa sta succedendo.

È inoltre possibile utilizzarlo per verificare se le procedure di esecuzione prolungata sono bloccate o aggiornare correttamente il database.

È fantastico se la tua azienda ama creare procedure memorizzate eccessivamente complesse.


6
La mia azienda ama creare procedure memorizzate eccessivamente complesse. Che grande idea per la risoluzione dei problemi!
Brandon,

22

Il vantaggio è che può essere più veloce in alcune situazioni. Lo svantaggio è che il risultato può essere errato (i dati non ancora commessi potrebbero essere restituiti) e non vi è alcuna garanzia che il risultato sia ripetibile.

Se ti interessa la precisione, non usare questo.

Ulteriori informazioni sono su MSDN :

Implementa la lettura sporca o il blocco del livello di isolamento 0, il che significa che non vengono emessi blocchi condivisi e non vengono rispettati blocchi esclusivi. Quando questa opzione è impostata, è possibile leggere dati non impegnati o sporchi; i valori nei dati possono essere modificati e le righe possono apparire o scomparire nel set di dati prima della fine della transazione. Questa opzione ha lo stesso effetto dell'impostazione di NOLOCK su tutte le tabelle in tutte le istruzioni SELECT in una transazione. Questo è il meno restrittivo dei quattro livelli di isolamento.


In che modo ciò influirebbe sulla velocità della query?
Kip Real

11
@Kip: le selectistruzioni non dovrebbero attendere per acquisire blocchi condivisi su risorse bloccate esclusivamente da altre transazioni.
Jarrod Dixon

15

Quando va bene usare READ UNCOMMITTED?

Regola del pollice

Buono : report aggregati di grandi dimensioni che mostrano totali in costante evoluzione.

Rischi : quasi tutto il resto.

La buona notizia è che la maggior parte dei rapporti di sola lettura rientrano in quella buona categoria.

Più dettaglio...

Ok per usarlo:

  • Quasi tutti i report aggregati rivolti all'utente per i dati attuali e non statici, ad esempio le vendite da inizio anno. Rischia un margine di errore (forse <0,1%) che è molto più basso rispetto ad altri fattori di incertezza come l'inserimento dell'errore o solo la casualità di quando i dati vengono registrati esattamente minuto per minuto.

Ciò copre probabilmente la maggior parte di ciò che un dipartimento di Business Intelligence farebbe, ad esempio, in SSRS. L'eccezione ovviamente, è qualcosa con $ segni davanti. Molte persone rappresentano denaro con molto più zelo di quello applicato alle metriche chiave correlate necessarie per servire il cliente e generare quel denaro. (Incolpo i ragionieri).

Quando è rischioso

  • Qualsiasi rapporto che scende al livello di dettaglio. Se tale dettaglio è richiesto, di solito implica che ogni riga sarà rilevante per una decisione. In effetti, se non puoi estrarre un piccolo sottoinsieme senza bloccarlo, potrebbe essere per la buona ragione che è attualmente in fase di modifica.

  • Dati storici. Raramente fa una differenza pratica, ma mentre gli utenti capiscono che i dati in costante cambiamento non possono essere perfetti, non provano la stessa cosa per i dati statici. Le letture sporche non fanno male qui, ma occasionalmente possono esserlo anche doppie letture. Visto che non dovresti comunque avere blocchi sui dati statici, perché rischiare?

  • Quasi tutto ciò che alimenta un'applicazione che ha anche capacità di scrittura.

Quando anche lo scenario OK non è OK.

  • Esistono applicazioni o processi di aggiornamento che utilizzano grandi transazioni singole? Quelli che rimuovono quindi reinseriscono molti record su cui stai segnalando? In tal caso, non è possibile utilizzare NOLOCKtali tabelle per nulla.

Un buon punto sui rapporti. In realtà la prima idea che mi è venuta in mente è stata se dovessi utilizzare read uncommittedper le applicazioni Web quando l'utente vede una griglia dell'interfaccia utente in cui l'accuratezza dei dati non è così importante. L'utente vuole solo una rapida panoramica di quali record potrebbero essere presenti, e magari con alcune funzioni di paginazione, ordinamento e filtro. Solo quando l'utente fa clic sul pulsante Modifica, allora provo a leggere il record più recente con un livello di isolamento più rigoroso. Tale approccio non dovrebbe essere migliore in termini di prestazioni?
JustAMartin,

Sì, penso sia ragionevole. Ricorda che il problema più significativo è assicurarsi che i dati non siano stati modificati da qualcun altro tra il momento in cui si preme il pulsante di modifica e il momento dell'invio. Potresti gestirlo avviando una transazione recuperando i dati come select item from things with (UPDLOCK). Metti un timeout veloce lì in modo che se non riesce ad acquisire il blocco velocemente, dica all'utente che è in fase di modifica. Ciò ti proteggerà non solo dagli utenti ma dagli sviluppatori. L'unico problema qui è che devi iniziare a pensare ai timeout e a come gestirli nell'interfaccia utente.
Adamantish,

6

Per quanto riguarda il reporting, lo utilizziamo su tutte le nostre query di reporting per impedire a una query di bloccare i database. Possiamo farlo perché stiamo estraendo dati storici, non dati aggiornati al microsecondo.


4

Utilizza READ_UNCOMMITTED in situazioni in cui è altamente improbabile che l'origine cambi.

  • Durante la lettura di dati storici. ad esempio alcuni registri di distribuzione avvenuti due giorni fa.
  • Durante la lettura dei metadati. ad es. applicazione basata su metadati.

Non utilizzare READ_UNCOMMITTED quando sai che la souce potrebbe cambiare durante l'operazione di recupero.


1
Sento che si applica il contrario. In primo luogo i dati statici devono essere letti bene senza blocchi. Se si fa bloccare allora hai ora scoperto c'è un importante problema di transazione appeso alla correzione. Inoltre, gli utenti si aspetteranno che corrispondano all'ultimo decimale, qualunque cosa abbiano stampato per il rapporto annuale dell'anno scorso. Generalmente non si aspettano lo stesso dai rapporti che sanno essere in costante flusso. Questo non vale per i report dettagliati, estremamente sensibili al tempo o finanziari, ma se 1 errore di immissione in 1000 è tollerabile, lo è anche READ UNCOMMITTED.
Adamantish,

TLDR: se i dati non cambiano, non è necessario LEGGERE SENZA COMPROMESSI perché non ci sono comunque blocchi. Se sbagli e cambia, allora è una buona cosa che hai impedito agli utenti di ottenere dati più sporchi del previsto.
Adamantish,

Sì, tendo a concordare con @Adamantish qui: puoi trarre vantaggio dalla READ UNCOMMITTEDmaggior parte delle situazioni in cui i tuoi dati vengono utilizzati attivamente e vuoi ridurre il carico sul server per evitare possibili deadlock e rollback delle transazioni solo perché alcuni utenti abusano incuratamente " Pulsante "Aggiorna" in una pagina Web con un datagrid. Gli utenti che visualizzano un sacco di record allo stesso tempo, di solito non si preoccupano molto se i dati sono un po 'obsoleti o parzialmente aggiornati. Solo quando un utente sta per modificare un record, potresti voler dargli i dati più accurati.
JustAMartin,

2

Questo ti darà letture sporche e ti mostrerà le transazioni che non sono state ancora impegnate. Questa è la risposta più ovvia. Non penso sia una buona idea usarlo solo per velocizzare le tue letture. Esistono altri modi per farlo se si utilizza una buona progettazione di database.

È anche interessante notare cosa non sta succedendo. READ UNCOMMITTED non ignora solo altri blocchi della tabella. Inoltre, non sta causando alcun blocco.

Si consideri che si sta generando un report di grandi dimensioni o che si sta migrando i dati dal database utilizzando un'istruzione SELECT grande e possibilmente complessa. Ciò causerà un blocco condiviso che può essere convertito in un blocco tabella condiviso per la durata della transazione. Altre transazioni possono essere lette dalla tabella, ma gli aggiornamenti sono impossibili. Questa potrebbe essere una cattiva idea se si tratta di un database di produzione poiché la produzione potrebbe interrompersi completamente.

Se si utilizza READ UNCOMMITTED, non verrà impostato un blocco condiviso sulla tabella. È possibile ottenere il risultato da alcune nuove transazioni o non dipendere da dove sono stati inseriti i dati della tabella e da quanto tempo è stata letta la transazione SELECT. È inoltre possibile ottenere gli stessi dati due volte se, ad esempio, si verifica una divisione della pagina (i dati verranno copiati in un'altra posizione nel file di dati).

Quindi, se è molto importante per te che i dati possano essere inseriti mentre fai il tuo SELECT, LEGGI UNCOMMITTED potrebbe avere senso. Devi considerare che il tuo rapporto può contenere alcuni errori, ma se si basa su milioni di righe e solo alcune di esse vengono aggiornate durante la selezione del risultato, questo potrebbe essere "abbastanza buono". La transazione potrebbe anche fallire tutti insieme poiché l'unicità di una riga potrebbe non essere garantita.

Un modo migliore potrebbe essere quello di utilizzare SNAPSHOT ISOLATION LEVEL ma le tue applicazioni potrebbero aver bisogno di alcune modifiche per usarlo. Un esempio di ciò è se l'applicazione utilizza un blocco esclusivo su una riga per impedire ad altri di leggerlo e passare alla modalità di modifica nell'interfaccia utente. SNAPSHOT ISOLATION LEVEL comporta anche una notevole penalità delle prestazioni (soprattutto su disco). Ma puoi superarlo lanciando hardware sul problema. :)

È inoltre possibile prendere in considerazione il ripristino di un backup del database da utilizzare per la creazione di report o il caricamento di dati in un data warehouse.


0

Può essere utilizzato per una tabella semplice, ad esempio in una tabella di controllo di solo inserimento, in cui non è presente alcun aggiornamento per la riga esistente e non viene visualizzato fk per un'altra tabella. L'inserto è un inserto semplice, che non ha o ha poche possibilità di rollback.


-7

Uso sempre READ UNCOMMITTED ora. È veloce con il minimo numero di problemi. Quando si utilizzano altri isolamenti, si incontrano quasi sempre alcuni problemi di blocco.

Fintanto che usi i campi Incremento automatico e presta un po 'più attenzione agli inserti, allora la tua sanzione, e puoi dire addio ai problemi di blocco.

Puoi fare errori con READ UNCOMMITED ma, a dire il vero, è molto semplice assicurarti che i tuoi inserti siano a prova completa. Inserti / aggiornamenti che utilizzano i risultati di una selezione sono gli unici aspetti a cui devi prestare attenzione. (Utilizzare READ COMMITTED qui o assicurarsi che letture sporche non causino problemi)

Quindi vai su Dirty Reads (Specialmente per grandi report), il tuo software funzionerà più agevolmente ...


6
Questo è molto impreciso e tocca solo la superficie dei problemi che possono verificarsi con nolock. Le pagine possono essere divise, i join possono non riuscire, è possibile leggere dati inesistenti o duplicare i dati. Non c'è modo di renderlo infallibile: non puoi fidarti dell'accuratezza di qualcosa sotto questo livello di isolamento. LEGGI L'
IMPIANTO IMPEGNATO

@MarkSowul Il downvoting di questa risposta mi sembra ingiusto. @Clive era chiaro che sarebbe passato a Committedinserimenti e aggiornamenti. Per quanto riguarda altri problemi, ha anche dimostrato la consapevolezza dei problemi di divisione della pagina menzionando l'utilizzo di una chiave di incremento automatico. Concordo con lui sul fatto che quasi tutti i rapporti in diretta fatti leggere solo da un essere umano possono tollerare lievi discrepanze nell'ultimo decimale. Concordo sul fatto che sia una storia diversa per elenchi dettagliati o dati destinati a essere letti e trasformati automaticamente, così come Clive.
Adamantish,

1
Questo commento dimostra anche una mancanza di piena comprensione dei possibili problemi che derivano da nolock. "Lievi discrepanze nella cifra decimale finale" non la coprono quasi. Anche toccare "usa solo read commit per inserimenti / aggiornamenti" è sbagliato come consiglio generale (e se fosse "inserisci un record se non esiste"?). In ogni caso, "[leggi non confermato] è veloce con il minor numero di problemi" è categoricamente sbagliato.
Mark Sowul,

Per la cronaca, sono d'accordo con la tua risposta, Adamantish: aggregazioni approssimativamente accurate e poco altro.
Mark Sowul,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.