Qualcuno può spiegare il motivo per cui selezionare con nolock interroga una pozione di dati aggiornati?
-
16-10-2019 - |
Domanda
Stavo leggendo la risposta da qui (da StackOverflow, credo che dovrebbe chiedere qui)
mezzi NOLOCK immissione serrature a tutti.
La vostra query potrebbe restituisce porzioni di dati come di prima dell'aggiornamento e porzioni di come dopo UPDATE in una singola query.
Mi capita che nolock non sarà posto di blocco al tavolo, in modo che altre persone possano interrogare contemporaneamente.
Dalla risposta e l'esempio è mostrare, è recuperare i dati, mentre i dati vengono aggiornamento.
Perché succede questo?
Io parto dal presupposto per il normale selezionarlo cercherà posto di blocco sul tavolo, in modo che quando si esegue un'istruzione di aggiornamento, è mettere un lucchetto alla riga o pagina. Poi, quando provo a fare funzionare dichiarazione prescelta, non può mettere il blocco fino a quando il blocco istruzione di aggiornamento viene rilasciato.
Ma in questo caso perché l'istruzione select non cerca di mettere blocco sul tavolo, in modo che possa funzionare senza attendere la dichiarazione di aggiornamento rilasciare il blocco?
Soluzione
It is not quite true that NOLOCK
means placing no locks at all. Queries under this hint will still take Sch-S
locks and (possibly HOBT
locks).
Under read committed
isolation level SQL Server will (usually) take row level S
locks and release them as soon as the data is read. These are incompatible with the X
locks held on uncommited updates and thus prevent dirty reads.
In the example in the linked answer the SELECT
query is not blocked when it encounters a modified row so reading partial updates is quite likely.
It can also happen at default read committed
isolation level too though that a SELECT
reads some rows with the "before" value and others with the "after" value. It is just needed to engineer a situation where
- Select query reads value of row
R1
and releases itsS
lock - Update query updates
R2
and takes anX
lock - Select query tries to read
R2
and is blocked. - Update query updates
R1
and takes anX
lock. - Update transaction commits thus releasing its locks and allowing the Select to read
R2
This type of situation might arise for example if the SELECT
and UPDATE
are using different indexes to locate the rows of interest.
Example
CREATE TABLE T
(
X INT IDENTITY PRIMARY KEY,
Y AS -X UNIQUE,
Name varchar(10),
Filler char(4000) DEFAULT 'X'
)
INSERT INTO T (Name)
SELECT TOP 2500 'A'
FROM master..spt_values
Now in one query window run
DECLARE @Sum int
SELECT 'SET @@ROWCOUNT' WHERE 1=0
WHILE (@@ROWCOUNT = 0)
SELECT @Sum = SUM(LEN(Name))
FROM T
WHERE Y IN (-1, -2500)
HAVING SUM(LEN(Name)) = 3
This will run in an infinite loop. In another run
UPDATE T
SET Name=CASE WHEN Name = 'A' THEN 'AA' ELSE 'A' END
This will likely stop the loop in the other query (try again if not) meaning that it must have read either A,AA
or AA,A
Altri suggerimenti
The hint NOLOCK
is equivalent to the transaction isolation level READ UNCOMMITTED
, just restricted to the scope of one table access method.
What RU does that makes the non-committed appear on your resultset? Hmm, actually is a question of "what it not does. I'll explain below.
Well (this is a gross simplification, I know) MSSQL (in its' default behavior) is a lock engine - which means that it uses lock to read/write data on a consistent manner. In this oversimplified explanation, MSSQL uses two kinds of locks: shared lock and exclusive lock.
An shared(S) lock is a lock that allow an resource (which can be a row, page of rows or even an entire table) to be read - but not allows an write to it. So if transaction T1 puts a S lock on R1 row, all transactions that tries to read R1 will get that read, but while the S lock is alive nobody can write to R1.
An exclusive(X) lock is the counterpart of the shared lock. It allows exclusive access to a resource - no other transaction can read or write except the one that got the X lock. In the above example, if T1 got not an S lock but an X lock on R1, no one except T1 can read or write it.
That's the teory. The isolation levels honor the locks, and respect their prevalence and characteristics. All, except READ UNCOMMITTED
. It simple gives a * (put your bad mouth word of your preference here) to the locks regarding the reading - you still cannot update the row another transaction got an X lock. It simply says: "I'll read everything that's relevant to the query plan - disregard what locks are on it."
And do it.