Che cos'è "with (nolock)" in SQL Server?


610

Qualcuno può spiegare le implicazioni dell'uso with (nolock)sulle query, quando non dovresti / non dovresti usarlo?

Ad esempio, se si dispone di un'applicazione bancaria con tassi di transazione elevati e molti dati in determinate tabelle, in quali tipi di query non andrebbe bene? Ci sono casi in cui dovresti sempre usarlo / non usarlo mai?




1
Ecco un eccellente riassunto delle implicazioni dell'utilizzo di NOLOCK blogs.msdn.com/b/davidlean/archive/2009/04/06/…
Bryan,

Risposte:


461

WITH (NOLOCK) è l'equivalente dell'utilizzo di READ UNCOMMITED come livello di isolamento della transazione. Pertanto, si corre il rischio di leggere una riga senza commit che viene successivamente ripristinata, ovvero i dati che non sono mai stati inseriti nel database. Pertanto, sebbene possa impedire il blocco delle letture da parte di altre operazioni, comporta un rischio. In un'applicazione bancaria con alti tassi di transazione, probabilmente non sarà la soluzione giusta per qualsiasi problema che stai cercando di risolvere con esso.


156
La maggior parte delle applicazioni bancarie può utilizzare nolock in modo sicuro perché sono transazionali in senso commerciale. Scrivi solo nuove righe, non le aggiorni mai.
Jonathan Allen,

49
@ Grauenwolf- Una riga inserita ma non impegnata potrebbe comunque portare a letture sporche.
Saasman,

16
@ Saasman- Se non esegui mai il rollback delle transazioni, non importa. E con una tabella di solo inserimento, le possibilità di un rollback sono ridotte a nessuno. E se si verificano, risolverai comunque tutto nel rapporto sulla varianza di fine giornata.
Jonathan Allen,

1
Sono trincerato. Presumo che il suggerimento Aggiunto nessun blocco sia attivo. Per esempio:
Ross Bush, l'

11
Se lo usi NOLOCKcon un SELECTcorri il rischio di restituire le stesse righe più di una volta (dati duplicati) se i dati vengono mai inseriti (o aggiornati) nella tabella mentre fai una selezione.
Ian Boyd,

170

La domanda è cosa è peggio:

  • un punto morto, o
  • un valore sbagliato?

Per i database finanziari, i deadlock sono molto peggiori dei valori errati. So che suona all'indietro, ma ascoltami. L'esempio tradizionale delle transazioni DB è l'aggiornamento di due righe, sottraendo da una e aggiungendole a un'altra. Questo è sbagliato.

In un database finanziario si utilizzano transazioni commerciali. Ciò significa aggiungere una riga a ciascun account. È della massima importanza che queste transazioni vengano completate e che le righe vengano scritte correttamente.

Misurare temporaneamente il saldo del conto non è un grosso problema, ecco a cosa serve la riconciliazione di fine giornata. E è molto più probabile che si verifichi uno scoperto da un conto perché due bancomat vengono utilizzati contemporaneamente rispetto a una lettura non impegnata da un database.

Detto questo, SQL Server 2005 ha corretto la maggior parte dei bug resi NOLOCKnecessari. Pertanto, a meno che non si utilizzi SQL Server 2000 o versioni precedenti, non è necessario.

Ulteriori letture
Versioning a livello di riga


22
Ottenere un saldo del conto temporaneamente errato non è un grosso problema? Cosa succede se quella transazione è quella in cui stai prelevando contanti da un bancomat senza alcun limite di scoperto?
Apprendimento del

13
@Learning: cosa succede se si estraggono i soldi 30 secondi prima che qualcuno addebiti la tua carta? Fino a quando tutte le comunicazioni non saranno istintive, gli scoperti saranno fatti della vita.
Jonathan Allen,

6
+1 Nell'app finanziaria (ovunque, non solo nelle banche), non ci sono né aggiornamenti né cancellazioni. Anche le operazioni errate vengono corrette inserendo i record. Qual è questo termine in inglese? È "storno"? Google non mi ha aiutato a rispondere a questa domanda
Gennady Vanin Геннадий Ванин

7
Entrata tardiva ... i deadlock devono essere catturati e riprovati. Le letture sporche hanno conseguenze
gbn

4
@JonathanAllen solo un fyi, il termine è UTmost, non UP.
Jimmy D

57

Sfortunatamente non si tratta solo di leggere dati non impegnati. Sullo sfondo potresti finire per leggere le pagine due volte (nel caso di una divisione di pagina) o potresti perdere del tutto le pagine. Quindi i tuoi risultati potrebbero essere molto distorti.

Dai un'occhiata all'articolo di Itzik Ben-Gan . Ecco un estratto:

"Con il suggerimento NOLOCK (o impostando il livello di isolamento della sessione su LEGGI UNCOMMITTED) dici a SQL Server che non ti aspetti coerenza, quindi non ci sono garanzie. Ricorda però che" dati incoerenti "non significa solo che è possibile che vengano visualizzate modifiche senza commit che sono state successivamente ripristinate o modifiche dei dati in uno stato intermedio della transazione. Ciò significa anche che in una semplice query che esegue la scansione di tutti i dati di tabella / indice SQL Server potrebbe perdere la posizione di scansione o si potrebbe finire ottenere la stessa riga due volte . "


5
Un po 'più in basso spiega come ottenere la stessa riga due volte: ricreerò la tabella T1 in modo tale che l'indice cluster su col1 verrà definito come un indice univoco con l'opzione IGNORE_DUP_KEY. Ciò significa che in col1 non possono esistere valori duplicati e anche che un tentativo di inserire una chiave duplicata non fallirà la transazione e genererà un errore piuttosto che generare un avviso. Se non usi questa strana opzione, probabilmente non dovrai preoccuparti di ottenere file due volte
JanHudecek,

È ancora possibile ottenere righe duplicate anche senza l'opzione cablata, ad esempio se la query utilizza un indice non univoco. Questo non è unico per nulla, però.
RMD

54

L'esempio del libro di testo per l'uso legittimo del suggerimento nolock è il campionamento dei report rispetto a un database OLTP con aggiornamento elevato.

Per fare un esempio attuale. Se una grande banca americana di strada voleva eseguire un rapporto orario alla ricerca dei primi segni di una corsa a livello di città sulla banca, una query non valida poteva scansionare le tabelle delle transazioni che sommavano depositi in contanti e prelievi di contanti per città. Per tale report, la minima percentuale di errore causata dalle transazioni di aggiornamento rollback non ridurrebbe il valore del report.


31

Non sono sicuro del motivo per cui non stai avvolgendo le transazioni finanziarie nelle transazioni del database (come quando trasferisci fondi da un conto a un altro - non commetti un lato della transazione alla volta - ecco perché esistono transazioni esplicite). Anche se il tuo codice è associato alle transazioni commerciali come sembra, tutte le banche dati transazionali hanno il potenziale per eseguire rollback impliciti in caso di errori o guasti. Penso che questa discussione sia finita per la testa.

In caso di problemi di blocco, implementare il controllo delle versioni e ripulire il codice.

Nessun blocco non restituisce solo valori errati ma restituisce record e duplicati fantasma.

È un'idea sbagliata comune che fa sempre funzionare le query più velocemente. Se non ci sono blocchi di scrittura su una tabella, non fa alcuna differenza. Se nella tabella sono presenti blocchi, è possibile che la query sia più veloce, ma in primo luogo è stato inventato un blocco.

In tutta onestà, qui ci sono due scenari speciali in cui un suggerimento nolock può fornire utilità

1) Database SQL Server pre-2005 che deve eseguire query lunghe su database OLTP live, questo potrebbe essere l'unico modo

2) Applicazione scritta male che blocca i record e restituisce il controllo all'interfaccia utente e i lettori vengono bloccati indefinitamente. Nolock può essere utile qui se l'applicazione non può essere riparata (terze parti ecc.) E il database è pre-2005 o non è possibile attivare il controllo delle versioni.


11
Sono d'accordo con te sul fatto che NOLOCK non dovrebbe essere usato per compensare il codice scritto male. Tuttavia, penso che il tuo attacco di Johnathan sia ingiustificato poiché non ha mai menzionato le transazioni del database . Stava semplicemente sottolineando che le applicazioni finanziarie in genere non consentono modifiche ai record (ovviamente ci sono alcune eccezioni). Nell'esempio di trasferimento di fondi, sta dicendo che sarebbe strano se si dovesse mutare il valore del saldo del conto invece di aggiungere una voce di debito / credito a una specie di libro mastro.
chrnola,

19
Quando i fondi vengono trasferiti da un conto a un altro presso diverse banche, cosa pensi che accada? Un super database si blocca su un tavolo della Bank of America e un altro su Wells Fargo? No. Una transazione finanziaria viene scritta per ciascuno e quindi un processo di fine giornata verifica che tutti i record corrispondano.
Jonathan Allen,

24

NOLOCKè equivalente a READ UNCOMMITTED, tuttavia Microsoft dice che non dovresti usarlo per UPDATEo DELETEdichiarazioni:

Per istruzioni UPDATE o DELETE: questa funzionalità verrà rimossa in una versione futura di Microsoft SQL Server. Evita di utilizzare questa funzione nel nuovo lavoro di sviluppo e pianifica di modificare le applicazioni che attualmente utilizzano questa funzione.

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

Questo articolo si applica a SQL Server 2005, quindi il supporto NOLOCKesiste se si utilizza quella versione. Al fine di rendere il tuo codice a prova di futuro (supponendo che tu abbia deciso di usare letture sporche) puoi usarlo nelle tue procedure memorizzate:

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED


21

Puoi usarlo quando stai solo leggendo i dati e non ti importa davvero se potresti recuperare o meno dati che non sono ancora stati impegnati.

Può essere più veloce in un'operazione di lettura, ma non posso davvero dire di quanto.

In generale, sconsiglio di utilizzarlo: la lettura di dati non impegnati può essere alquanto confusa.


1
sarebbe bello se tu avessi menzionato il fatto che SQL Server 2005 ha il controllo delle versioni delle righe, quindi non è più necessario nolocks.
Jonathan Allen,

Bene, "with (nolock)" ha ancora il suo posto anche in SQL Server 2005 - ma i vantaggi stanno diventando sempre più sottili, è vero.
marc_s,

18

Un altro caso in cui di solito va bene è in un database di report, in cui i dati sono forse già obsoleti e le scritture semplicemente non accadono. In questo caso, tuttavia, l'opzione deve essere impostata a livello di database o tabella dall'amministratore modificando il livello di isolamento predefinito.

Nel caso generale: si può utilizzare quando si è molto sicuro che è bene leggere i vecchi dati. La cosa importante da ricordare è che è molto facile sbagliare . Ad esempio, anche se va bene nel momento in cui scrivi la query, sei sicuro che qualcosa non cambierà nel database in futuro per rendere questi aggiornamenti più importanti?

Sarò anche secondo l'idea che probabilmente non è una buona idea nell'app bancaria. O app di inventario. O ovunque tu stia pensando alle transazioni.


4
Come persona che lavora su applicazioni bancarie, devo dire che i no-lock non sono un problema. I record transazionali, ovvero le righe inserite ma mai aggiornate o eliminate, sono sorprendentemente resistenti ai problemi di lettura dei dati non sottoposti a commit.
Jonathan Allen,

15

Risposta semplice: ogni volta che il tuo SQL non modifica i dati e hai una query che potrebbe interferire con altre attività (tramite blocco).

Vale la pena prendere in considerazione qualsiasi query utilizzata per i report, soprattutto se la query richiede più di, diciamo, 1 secondo.

È particolarmente utile se si dispone di report di tipo OLAP in esecuzione su un database OLTP.

La prima domanda da porsi, però, è "perché mi preoccupo di questo?" Nella mia esperienza, la confusione del comportamento di blocco predefinito spesso si verifica quando qualcuno è in modalità "prova qualsiasi cosa" e questo è un caso in cui non sono improbabili conseguenze impreviste. Troppo spesso è un caso di ottimizzazione prematura e può troppo facilmente rimanere incorporato in un'applicazione "per ogni evenienza". È importante capire perché lo stai facendo, quale problema risolve e se hai effettivamente il problema.


11

Risposta breve:

Utilizzare solo WITH (NOLOCK)nell'istruzione SELECT su tabelle con un indice cluster.

Risposta lunga:

WITH (NOLOCK) viene spesso sfruttato come un modo magico per accelerare le letture del database.

Il set di risultati può contenere righe non ancora impegnate, che spesso vengono successivamente ripristinate.

Se WITH (NOLOCK) viene applicato a una tabella che ha un indice non cluster, gli indici di riga possono essere modificati da altre transazioni mentre i dati di riga vengono trasmessi in streaming nella tabella dei risultati. Ciò significa che nel set di risultati possono mancare righe o visualizzare la stessa riga più volte.

READ COMMITTED aggiunge un ulteriore problema in cui i dati sono danneggiati all'interno di una singola colonna in cui più utenti cambiano la stessa cella contemporaneamente.


2
La lettura di dati non impegnati è accettabile se non cambia la decisione finale. Ad esempio, se stai cercando di proiettare quanti soldi il tuo negozio al dettaglio guadagnerà nei prossimi 6 mesi, visto che Tammy ha acquistato 2 rotoli di asciugamani di carta quando ne ha acquistati davvero 3 non cambierà la tua opinione sul futuro .
Jonathan Allen

1
Se il filtro include ora, i tuoi dati saranno inaccurati nel momento in cui esegui la query. Se il filtro include solo dati storici, l'utilizzo READ UNCOMITTED non influirà affatto. C'è un motivo per cui è stato incluso nello standard ANSI.
Jonathan Allen,

2
Mai dire mai. Se hai BISOGNO che i dati siano precisi al 100%, non dovresti usare nolock. Per me, questo di solito non è il caso. Quando si presentano i dati a un utente, al momento in cui agiscono sui dati, questi potrebbero essere già cambiati, ma molto probabilmente no, e la contesa con il blocco non vale i ritardi di risposta.
Perposterer,

Atteniamoci a sistemi degni di esistenza. Non dimenticare che Tammy ha un cervello perfettamente decente, quindi utilizzare un database per registrare piccoli acquisti di asciugamani di carta di cui nessuno se ne accorge è alquanto assurdo. Il nostro focus sono i sistemi che sono in realtà importanti, ad esempio ottenere persone pagate in tempo, rispondere alle emergenze, ecc. È di notevole beneficio che l'uso di WITH (NOLOCK) sia compreso dalle persone che programmano qualsiasi sistema degno di esistenza. Quando una persona può fare un lavoro migliore di un database, allora considera di riproporre quelle risorse.
WonderWorker,

10

I miei 2 centesimi - ha senso usare WITH (NOLOCK) quando è necessario generare report. A questo punto, i dati non cambieranno molto e non vorrai bloccare quei record.


2
Penso che WITH (NoLOCK) sia migliore se non ti interessano i cambiamenti attuali.
Abdul Saboor,

9

Se gestisci transazioni finanziarie, non vorrai mai più utilizzarle nolock. nolockè meglio usato per selezionare da tabelle di grandi dimensioni che hanno molti aggiornamenti e non ti interessa se il record che ottieni potrebbe non essere aggiornato.

Poiché i record finanziari (e quasi tutti gli altri record nella maggior parte delle applicazioni) nolockcauserebbero il caos poiché potresti potenzialmente rileggere i dati da un record su cui erano stati scritti e non ottenere i dati corretti.


5
Sorprendentemente, quando si lavora con dati finanziari questo non è un problema. Poiché le righe non vengono mai modificate e gli account vengono riconciliati alla fine della giornata, la lettura temporanea di dati fasulli non fa nulla.
Jonathan Allen,

8

Ho usato per recuperare un "prossimo batch" per le cose da fare. In questo caso non importa quale articolo esatto e ho molti utenti che eseguono la stessa query.


1
Facciamo qualcosa di simile per presentare un'attività in background con una coda di lavoro da fare. Se, quando arriva a un determinato record, non esiste più / corrisponde ai criteri di selezione, passa al successivo.
TripeHound,

7

Usa nolock quando stai bene con i dati "sporchi". Ciò significa che nolock può anche leggere i dati che sono in fase di modifica e / o dati non impegnati.

In genere non è una buona idea usarlo in un ambiente con transazioni elevate ed è per questo che non è un'opzione predefinita per le query.


3
L'unica volta che ti serve è in un ambiente di transazione elevato. Se i tuoi tavoli sono per lo più inattivi, non otterrai nulla da esso.
Jonathan Allen,

7

Uso con il suggerimento (nolock) in particolare nei database SQLServer 2000 ad alta attività. Tuttavia, non sono sicuro che sia necessario in SQL Server 2005. Di recente ho aggiunto quel suggerimento in un SQL Server 2000 su richiesta del DBA del client, perché stava notando molti blocchi di record SPID.

Tutto quello che posso dire è che l'uso del suggerimento NON ci ha fatto del male e sembra aver risolto il problema del blocco. Il DBA di quel particolare cliente ha sostanzialmente insistito sul fatto che usiamo il suggerimento.

A proposito, i database di cui mi occupo sono back-end ai sistemi di reclami medici aziendali, quindi stiamo parlando di milioni di record e oltre 20 tabelle in molti join. In genere aggiungo un suggerimento WITH (nolock) per ogni tabella nel join (a meno che non sia una tabella derivata, nel qual caso non è possibile utilizzare quel particolare suggerimento)


1
SQL Server 2005 ha aggiunto il "versioning delle righe" che dovrebbe ridurre notevolmente la necessità di nolocks. Di recente abbiamo effettuato l'upgrade e non stiamo addestrando i nostri DBA a smettere di usarli.
Jonathan Allen,

5

La risposta più semplice è una domanda semplice: hai bisogno che i tuoi risultati siano ripetibili? In caso affermativo, NOLOCKS non è appropriato in nessun caso

Se non è necessaria la ripetibilità, allora nolocks può essere utile, soprattutto se non si ha il controllo su tutti i processi di connessione al database di destinazione.

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.