Gli hint di tabella consentono di modificare il comportamento predefinito di Query Optimizer per la durata dell’istruzione DML (Data Manipulation Language) specificando un metodo di blocco, uno o più indici, un’operazione di elaborazione di query, quale un’analisi di tabella (Table Scan) o una ricerca nell’indice (Index Seek), oppure altre opzioni [1].
La sintassi è la seguente:
WITH ( <table_hint> ) [ [, ]...n ]
NOLOCK (READUNCOMMITTED)
Questo comando permette di evitare il blocco dei dati dovuti ad una transazione non chiusa.
Spieghiamo il funzionamento di questo comando con un esempio:
La query seguente ritorna tutti i record della tabella Contact
SELECT * FROM Person.Contact
Ora assumiamo che vi sia un secondo utente che lancia la query sopra in una transazione (senza chiuderla). La query viene completata e i record aggiornati, ma non essendo stata committata i record su DB sono LOCKED.
SELECT * FROM Person.Contact
BEGIN TRAN
UPDATE Person.Contact SET Suffix = 'B'
-- ROLLBACK or COMMIT
Conseguentemente se io lancio ancora la query di UPDATE indicata sopra, questa non terminerà mai, in quanto l’UPDATE non è stato committato.
Per verificare questo posso usare la stored procedure sp_who2
EXEC sp_who2
Che fornisce una serie di informazioni sui processi in atto sul server, in questo caso mi permette di vedere che l’istruzione SELECT
è stata bloccata (AWAITING COMMAND
).
Devo o cancellare l’esecuzione della query o eseguire un COMMIT
o ROLLBACK
dell’istruzione appena eseguita.
Per evitare il problema dei record bloccati prima di un commit posso usare unWITH (NOLOCK)
che completerà la query anche se i record in questione sono bloccati in quanto un’altra transazione è in esecuzione.
SELECT * FROM Person.Contact WITH (NOLOCK)
Questa operazione esegue una lettura sporca (Dirty read) in quanto sto leggendo dei dati che non so se esistono veramente (all’update seguirà un commit
) o no (all’update seguirà un rollback
).
Quindi se sto banalmente mostrando dei record posso usare il NOLOCK
senza preoccupazioni, se però devo lavorare con dei dati consistenti allora questa soluzione mi espone al rischio di lavorare con dei dati falsi.
Il comando NOLOCK
è un sinonimo di READUNCOMMITED
e possono essere usati equivalentamentemente.
SELECT * FROM Person.Contact WITH (READUNCOMMITTED)
E’ da sottolineare il fatto che questi comandi sono compatibili solo con un istruzione di SELECT
.
Effetti del NOLOCK
- Lettura sporca: come indicato sopra, posso leggere dati che non esistono
- Righe mancanti: altre transazioni possono muovere che non hai ancora letto in un posto in cui hai invece appena letto, perdendo conseguentemente tali dati
- Righe duplicate: simmetricamente a quanto indicato sopra, posso leggere due volte la stessa riga
- Leggere versioni multiple della stessa riga
- Errori in lettura: dato che posso poter leggere dei dati che sono stati spostati durante la lettura, potrei incorrere in questo errore:
Could not continue scan with NOLOCK due to data movement.
Per approfondire consiglio i seguenti articoli: