Leggi livello di isolamento Committed in SQL Server per una singola istruzione
-
23-10-2019 - |
Domanda
Di ', ho una tabella persona e ha solo 1 fila -
id = 1, name = 'foo'
In una connessione
select p1.id, p1.name, p2.name
from person p1
join person p2 on p1.id = p2.id
In un altro collegamento allo stesso tempo:
update person set name = 'bar' where person.id = 1
Q1: È mai possibile, per il mio selezionare per restituire un risultato come questo in base alla tempistica della dichiarazione di aggiornamento:
id = 1, p1.name = 'foo', p2.name = 'bar'
Né connessione utilizza una transazione esplicita ed entrambi livello di isolamento di difetto di uso LEGGI commesso.
La domanda è: è davvero di aiutarmi a capire, se i blocchi acquisiti all'inizio di un'istruzione SQL continuano ad esistere fino al completamento istruzione, o se è possibile che una dichiarazione per rilasciare il blocco e ri-acquisire il blocco per la stessa riga se viene utilizzato due volte nella stessa istruzione?
Q2:? Se la soluzione al cambiamento domanda se il set read_committed_snapshot on
è impostato sul db
Soluzione
Q1: Sì, questo è perfettamente possibile, almeno in teoria. read committed
garantisce solo che tu non leggere dati sporchi che non fa promesse di coerenza. A livello impegnati leggere blocchi condivisi vengono rilasciati non appena i dati vengono letti (non alla fine della transazione o anche la fine dell'istruzione)
Q2: Sì, la risposta a questa domanda sarebbe cambiare se read_committed_snapshot
è acceso. Si potrebbe quindi essere garantito livello di istruzione di coerenza. Sto trovando difficoltà a trovare una fonte online che indica in modo inequivocabile questo, ma citando p.648 di "Microsoft SQL Server 2008 Internals"
Una dichiarazione in RCSI vede tutto commesso prima dell'inizio della dichiarazione. Ogni nuova dichiarazione in raccoglie transazione fino al più recente cambiamenti inseriti.
vedere questo MSDN post sul blog
Impostazione script
CREATE TABLE person
(
id int primary key,
name varchar(50)
)
INSERT INTO person
values(1, 'foo');
Connessione 1
while 1=1
update person SET name = CASE WHEN name='foo' then 'bar' ELSE 'foo' END
Connessione 2
DECLARE @Results TABLE (
id int primary key,
name1 varchar(50),
name2 varchar(50))
while( NOT EXISTS(SELECT *
FROM @Results) )
BEGIN
INSERT INTO @Results
Select p1.id,
p1.name,
p2.name
from person p1
INNER HASH join person p2
on p1.id = p2.id
WHERE p1.name <> p2.name
END
SELECT *
FROM @Results
Risultati
id name1 name2
----------- ----- -----
1 bar foo
Guardando l'altro tipi di join in Profiler sembra che la questione non poteva nascere sotto sia la merge
aderire o piano nested loops
per questo particolare query (serrature vengono rilasciati fino a quando tutti sono acquisiti), ma i resti di punti che read committed
solo vi garantisce non leggere dati sporchi che non fa promesse circa la coerenza. In pratica si può anche non avere questo problema per la query esatto avete pubblicato come SQL Server non sarebbe scegliere questo tipo si uniscono per impostazione predefinita. Tuttavia si sono poi appena lasciato basandosi su dettagli di implementazione per produrre il comportamento che si desidera.
NB: Se vi stavate chiedendo il motivo per cui alcuni blocchi a livello di riga S
sembrano mancare questo è un'ottimizzazione spiegato qui .