Modifica: Come sottolinea @MaxVernon , il seguente non è in alcun modo un suggerimento per usare NOLOCK , e avrei dovuto menzionare il settaggio del livello di transazione READ UNCOMMITED
e lasciare che la connotazione negativa rimanga lì piuttosto che far NOLOCK
apparire in primo luogo. Quindi, come originariamente pubblicato:
Il rapido e semplice è "Sì, la prima query bloccherà la seconda query a meno che non venga specificato un suggerimento di indice specifico ( NOLOCK , a volte chiamato" lettura sporca ") o il livello di isolamento della transazione della seconda query sia impostato su READ UNCOMMITED
(che funziona in modo identico), no non lo fa."
In risposta ai dettagli aggiuntivi forniti nella domanda che comporta l'inclusione di una WITH
clausola sulla seconda SELECT
, essendo reciprocamente esclusivi o meno, le interazioni tra le due query saranno sostanzialmente le stesse.
IF NOT EXISTS ( SELECT 1
FROM sys.objects
WHERE name = 'Foo'
AND type = 'U' )
BEGIN
--DROP TABLE dbo.Foo;
CREATE TABLE dbo.Foo
(
Foo_PK BIGINT IDENTITY( 1, 1 ) NOT NULL,
PRIMARY KEY ( Foo_PK ),
Bar BIT,
x BIT,
y BIT,
z BIT
);
CREATE NONCLUSTERED INDEX IX_Foo_x
ON dbo.Foo ( x );
INSERT INTO dbo.Foo ( Bar, x, y, z )
VALUES ( 1, 1, 1, 1 ), ( 0, 0, 0, 0 );
END;
GO
BEGIN TRANSACTION;
UPDATE dbo.Foo
SET y = 0
WHERE x = 1;
-- COMMIT TRANSACTION;
In una sessione separata, eseguire quanto segue:
SELECT *
FROM dbo.Foo WITH ( NOLOCK );
GO
SELECT *
FROM dbo.Foo;
Puoi esaminare i blocchi attualmente in esecuzione eseguendo sp_lock
, preferibilmente in un'altra sessione separata:
EXECUTE dbo.sp_lock;
Dovresti vedere un KEY
blocco di tipo trattenuto dallo spid che esegue la transazione di inserimento in X
modalità (esclusiva), da non confondere con gli altri IX
blocchi (Intent-Exclusive). La documentazione del blocco indica che mentre il KEY
blocco è specifico dell'intervallo, impedisce anche ad altre transazioni di inserire o aggiornare le colonne interessate modificando i dati in essa contenuti in modo che possano rientrare in quell'intervallo della query originale. Poiché il blocco stesso è esclusivo, la prima query impedisce l'accesso alla risorsa da qualsiasi altra transazione simultanea. In effetti, tutte le righe della colonna sono bloccate, indipendentemente dal fatto che rientrino o meno nell'intervallo specificato dalla prima query.
Il S
blocco che viene trattenuto dalla seconda sessione sarà quindi WAIT
fino a quando il X
blocco non si cancella, impedendo che un altro X
(o U
) blocco venga prelevato su quella risorsa da un diverso spid simultaneo prima che la seconda sessione completi l'operazione di lettura, giustificando l'esistenza del S
blocco.
Ora una modifica per chiarezza: a meno che non mi sbagli in ciò che è una lettura sporca dalla breve descrizione dei rischi menzionati qui ... Modifica 3 : Ho appena realizzato che non sto prendendo in considerazione l'effetto di un checkpoint di sfondo che scrive un di transazione su disco non ancora impegnata, quindi sì, la mia spiegazione era fuorviante.
Nella seconda query, il primo batch può (e in questo caso, restituirà) dati non impegnati. Il secondo batch, in esecuzione nel livello di isolamento della transazione predefinito di, READ COMMITED
verrà restituito solo dopo il completamento di un commit o rollback nella prima sessione.
Da qui puoi esaminare i piani di query e i livelli di blocco associati, ma meglio ancora, puoi leggere tutto sui blocchi in SQL Server qui .
SELECT * FROM Table1
se è esattamente quello di cui ho bisogno?