Letture sporche di SQL Server 2008 R2: quanto non atomiche?


11

Mi chiedo "quanto sporche" le letture sporche possano arrivare a un livello di isolamento non letto . Comprendo che le righe che sono state aggiornate ma non ancora impegnate sono visibili, ma:

  1. Una riga può apparire come parzialmente aggiornata, ovvero alcune delle colonne vengono aggiornate e altre no?
  2. Una singola colonna può apparire parzialmente aggiornata. Ad esempio, se si dispone di una colonna varchar (4000) che era in fase di aggiornamento completo e si presuppone che contenga effettivamente 4000 caratteri. Puoi leggere i caratteri 2k del precedente stato e i caratteri 2k del suo nuovo stato? Che dire di varchar (max) con lunghezza> 8k?

Aggiornamento: dopo alcuni dibattiti, il consenso minimo è che se la dimensione della colonna è> 8 KB, sono possibili letture sporche, anche all'interno della colonna stessa.

Risposte:


7

MODIFICATO dopo aver letto il link al forum MSDN dal commento , molto interessante.

Indipendentemente dal livello di isolamento, due utenti non possono aggiornare contemporaneamente una singola pagina , né nessun utente può leggere una pagina parzialmente aggiornata. Immagina come SQL Server gestirà una pagina in cui l'intestazione dice che Col3 inizia al byte 17. Ma inizia davvero al byte 25, perché quella parte della riga non è stata ancora aggiornata. Non è possibile che un database possa gestirlo.

Ma per le righe più grandi di 8k, vengono utilizzate più pagine e ciò rende possibile una colonna semi-aggiornata. Copiato dal collegamento MSDN (in caso di interruzione del collegamento), avvia questa query in una finestra:

if object_id('TestTable') is not null
    drop table TestTable
create table TestTable (txt nvarchar(max) not null)
go
insert into TestTable select replicate(convert(varchar(max),
    char(65+abs(checksum(newid()))%26)),100000)
go 10
update TestTable set txt=replicate(convert(varchar(max),
    char(65+abs(checksum(newid()))%26)),100000)
go 100000

Questo crea una tabella e quindi la aggiorna con una stringa di 100.000 volte lo stesso carattere. Mentre la prima query è in esecuzione, avvia questa query in un'altra finestra:

while 1=1 begin
 if exists (select * from TestTable (nolock) where left(Txt,1) <> right(Txt,1))
    break
end

La seconda query si interrompe quando legge una colonna che è semi-aggiornata. Cioè, quando il primo personaggio è diverso dall'ultimo. Finirà rapidamente, dimostrando che è possibile leggere colonne semi-aggiornate. Se rimuovi il nolocksuggerimento, la seconda query non finirà mai.

Risultato sorprendente! Una colonna XML semi-aggiornata potrebbe interrompere un (nolock)report, poiché l'XML sarebbe errato.


1
Apparentemente questo non è sempre vero, per social.msdn.microsoft.com/Forums/en-US/transactsql/thread/… , ma quali tipi di colonne possono essere visti parzialmente aggiornati è ancora un po 'un mistero.

@Andomar I latch AFAIK impedirebbero le letture di una pagina parzialmente aggiornata, ma cosa succede se alcuni valori di colonna fossero letti da un NCI ma facesse una ricerca nei segnalibri per recuperare una colonna dall'IC. Sotto NOLOCKsono sicuro che sarebbe possibile progettare una situazione in cui le colonne NCI provenivano da una versione della riga ma l'IC da una versione diversa. Inoltre, i dati fuori riga e le pagine dei lob non sarebbero protetti dal fermo sulla pagina dei dati.
Martin Smith,

1
@Martin: D'accordo, ho visto un self join che nolocknon ha trovato la sua riga originale. Tuttavia, una singola lettura di un campo o di una riga deve essere coerente.
Andomar,

1
@Andomar, a meno che le colonne nella riga si estendano su più pagine. Vedi il mio link

2
Questo dovrebbe davvero essere CW perché la risposta originale non era affatto giusta, Michael ha fornito l'essenza della risposta attuale. Il tuo commento contro la domanda non è ancora d'accordo con la risposta modificata.
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.