NOLOCK è sempre male?


34

Sono uno sviluppatore di report che desidera rendere le mie query il più efficienti possibile. Lavoravo con un DBA che mi diceva - credo perché mi occupavo sempre di report su un server di produzione - da utilizzare NOLOCKin ogni singola query.

Ora lavoro con un DBA che ha vietato NOLOCKin qualsiasi circostanza - anche quando un mio rapporto (a causa di una considerevole mancanza di indici su un paio di tabelle) sta interrompendo la replica e gli aggiornamenti di sistema. Secondo me, in questo caso, NOLOCKsarebbe una buona cosa.

Dal momento che la maggior parte del mio addestramento SQL è arrivato a vari DBA con opinioni molto diverse, volevo chiedere questo a una vasta gamma di DBA.


1
L'altro lato di questa discussione: dba.stackexchange.com/q/2684/2660
Nick Chammas

Risposte:


30

Se il tuo report blocca gli aggiornamenti che il tuo DBA ha ragione: non dovresti assolutamente utilizzarlo NOLOCK. Il fatto stesso che ci siano conflitti è una chiara indicazione che, se si desidera utilizzare letture sporche si otterrebbe rapporti non corretti.

Secondo me, ci sono sempre alternative migliori di NOLOCK:

  • Le tue tabelle di produzione vengono lette solo in effetto e non vengono mai modificate? Segna il database in sola lettura!
  • Le scansioni delle tabelle causano conflitti di blocco? Indicizza le tabelle in modo appropriato, i vantaggi sono molteplici.
  • Non riesci a modificare / non sai indicizzare in modo appropriato? Usa ISOLAMENTO SNAPSHOT .
  • Non è possibile cambiare app per usare l'istantanea? Attiva lettura istantanea impegnata !
  • Hai misurato l'impatto del controllo delle versioni delle righe e hai prove che influiscono sulle prestazioni? Non puoi indicizzare i dati? e stai bene con rapporti errati ? Quindi almeno fatevi un favore e un uso SET TRANSACTION ISOLATION LEVEL, non un suggerimento per la query. In seguito sarà più semplice correggere il livello di isolamento invece di modificare ogni query.

6
Fai attenzione: l'attivazione della lettura dell'istantanea impegnata potrebbe interrompere la codifica.
AK,

33

Non è sempre male.

Ovviamente ti permette di leggere valori non impegnati (che possono essere ripristinati e quindi non esistevano mai logicamente) oltre a consentire fenomeni come la lettura di valori più volte o per niente.

Gli unici livelli di isolamento che garantiscono che non si verificheranno tali anomalie sono serializzabili / istantanee. Se i valori di lettura ripetibili possono essere persi se una riga viene spostata (a causa di un aggiornamento della chiave) prima che la scansione raggiunga questa riga, i valori di commit letti possono essere letti due volte se un aggiornamento della chiave fa avanzare una riga precedentemente letta.

nolockTuttavia, è più probabile che si verifichino questi problemi perché, per impostazione predefinita, a questo livello di isolamento utilizzerà una scansione ordinata per allocazione quando stima che ci siano più di 64 pagine da leggere . Oltre alla categoria di problemi che sorgono quando le righe si spostano tra le pagine a causa degli aggiornamenti delle chiavi dell'indice, queste scansioni ordinate per allocazione sono anche vulnerabili ai problemi con le suddivisioni di pagina (dove è possibile perdere le righe se la pagina appena allocata è precedente nel file rispetto al punto già scansionato o letto due volte se una pagina già scansionata è divisa in una pagina successiva nel file).

Almeno per semplici query (a tabella singola) è possibile scoraggiare l'uso di queste scansioni e ottenere una scansione ordinata per chiave nolocksemplicemente aggiungendo una ORDER BY index_keyalla query in modo che la Orderedproprietà di IndexScansia true.

Ma se la tua applicazione di segnalazione non ha bisogno di cifre assolutamente precise e può tollerare la maggiore probabilità di tali incoerenze, potrebbe essere accettabile.

Ma certamente non dovresti buttarlo su tutte le domande nella speranza che sia un pulsante "turbo" magico. Oltre alla maggiore probabilità di incontrare risultati anomali a quel livello di isolamento o nessun risultato (errore "Impossibile continuare la scansione con NOLOCK a causa del movimento dei dati") ci sono anche casi in cui le prestazioni con nolock possono essere molto peggiori .


3
+1 - Lo usiamo molto perché le nostre tabelle di produzione non vengono mai modificate.
JNK,

@JNK Che cosa intendi con non viene mai modificato?
Kuberchaun,

4
Martin, suggerirei parole leggermente diverse: "i valori di commit letti possono essere persi e letti più di una volta". In alcuni casi esotici è possibile recuperare una riga più di due volte.
AK,

@ StarShip3000 I dati che distribuiamo alla produzione sono sostanzialmente di sola lettura per gli utenti finali, quindi la maggior parte delle loro visualizzazioni ha suggerimenti NOLOCK
JNK

11

I vostri clienti tollerano risultati incoerenti nei report? Se la risposta è no, non dovresti usare NOLOCK: puoi ottenere risultati errati in concomitanza. Ho scritto alcuni esempi qui , qui e qui . Questi esempi mostrano output incoerenti in READ COMMITTED e REPEATABLE READ, ma puoi modificarli e ottenere risultati errati anche con NOLOCK.


La maggior parte dei report che creo non vengono eseguiti sui dati correnti. La maggior parte dei clienti sta eseguendo report sono i dati di ieri. La tua risposta cambierebbe se fosse così?
DataGirl,

8

La maggior parte dei report che creo non vengono eseguiti sui dati correnti. La maggior parte dei clienti sta eseguendo report sono i dati di ieri. La tua risposta cambierebbe se fosse così?

In tal caso, hai un'altra opzione possibile:
Invece di eseguire le tue query sul database di produzione e fare scherzi con i blocchi NOLOCK, puoi eseguire i tuoi rapporti da una copia del database di produzione.

Puoi configurarlo in modo che venga automaticamente ripristinato da un backup ogni notte .
Apparentemente i tuoi rapporti sono in esecuzione su server nei siti dei clienti, quindi non so se l'impostazione sarebbe una soluzione praticabile per te.
(ma poi di nuovo ... dovrebbero avere comunque dei backup, quindi tutto ciò che serve è un po 'di spazio sul server per ripristinarli)

Sono uno sviluppatore interno, quindi questo è più facile per me perché ho il pieno controllo dei server e dei database.

Puoi farlo almeno per i rapporti che richiedono solo dati di ieri e precedenti. Forse alcuni report dovranno rimanere nel database di produzione, ma almeno si sposta un po 'del carico in un altro database (o ancora meglio, in un altro server).

Ho anche la stessa situazione al lavoro:
stiamo usando una copia del database di produzione come questa per quasi tutte le informazioni sui rapporti, ma ci sono alcune query che richiedono i dati di oggi.


Mi piace la tua risposta e funzionerebbe, se avessi il pieno controllo, cosa che non ho fatto. Spesso, non ho il pieno controllo e non riesco a creare indici. Sono fortunato se posso eseguire / visualizzare i piani di esecuzione.
DataGirl
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.