SQL Server 2008 R2 Dirty Reads - wie nicht atomar?

11

Ich frage mich, "wie schmutzig" schmutzige Lesevorgänge unter eine nicht festgeschriebene Isolationsstufe geraten können . Ich verstehe, dass Zeilen, die aktualisiert, aber noch nicht festgeschrieben wurden, sichtbar sind, aber:

  1. Kann eine Zeile als teilweise aktualisiert angezeigt werden, dh einige der Spalten werden aktualisiert, andere nicht?
  2. Kann eine einzelne Spalte teilweise aktualisiert erscheinen? Wenn Sie beispielsweise eine varchar (4000) -Spalte haben, die gerade vollständig aktualisiert wurde und davon ausgeht, dass sie tatsächlich 4000 Zeichen enthält. Können Sie sagen, 2k Zeichen aus dem vorherigen Zustand und 2k Zeichen aus dem neuen Zustand? Was ist mit Varchar (max) mit einer Länge> 8k?

Update: Nach einigen Diskussionen besteht der minimale Konsens darin, dass bei einer Spaltengröße von> 8 KB Dirty Reads auch innerhalb der Spalte selbst möglich sind.

Michael Goldshteyn
quelle

Antworten:

7

BEARBEITET nach dem Lesen des MSDN-Forum-Links aus dem Kommentar , sehr interessant.

Unabhängig von der Isolationsstufe können zwei Benutzer weder eine einzelne Seite gleichzeitig aktualisieren, noch kann ein Benutzer eine teilweise aktualisierte Seite lesen. Stellen Sie sich vor, wie SQL Server mit einer Seite umgehen würde, auf der laut Header Col3 bei Byte 17 beginnt. Aber es beginnt wirklich bei Byte 25, da dieser Teil der Zeile noch nicht aktualisiert wurde. Eine Datenbank kann damit auf keinen Fall umgehen.

Bei Zeilen, die größer als 8 KB sind, werden jedoch mehrere Seiten verwendet. Dies ermöglicht eine halb aktualisierte Spalte. Starten Sie diese Abfrage in einem Fenster, das vom MSDN-Link kopiert wurde (falls der Link unterbrochen wird):

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

Dadurch wird eine Tabelle erstellt und anschließend mit einer Zeichenfolge von 100.000x demselben Zeichen aktualisiert. Starten Sie diese Abfrage, während die erste Abfrage ausgeführt wird, in einem anderen Fenster:

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

Die zweite Abfrage wird beendet, wenn eine zur Hälfte aktualisierte Spalte gelesen wird. Das heißt, wenn sich das erste Zeichen vom letzten unterscheidet. Es wird schnell beendet und beweist, dass es möglich ist, halb aktualisierte Spalten zu lesen. Wenn Sie den nolockHinweis entfernen , wird die zweite Abfrage niemals beendet.

Überraschendes Ergebnis! Eine halb aktualisierte XML-Spalte kann einen (nolock)Bericht beschädigen, da das XML fehlerhaft ist.

Andomar
quelle
1
Dies ist anscheinend nicht immer der Fall, laut social.msdn.microsoft.com/Forums/en-US/transactsql/thread/… , aber welche Spaltentypen teilweise aktualisiert angezeigt werden , ist immer noch ein Rätsel.
@Andomar AFAIK-Latches würden das Lesen einer teilweise aktualisierten Seite verhindern, aber was wäre, wenn einige Spaltenwerte von einer NCI gelesen würden, aber eine Lesezeichensuche durchgeführt würde, um eine Spalte aus dem CI abzurufen. Unter NOLOCKmir sicher bin , wäre es möglich, eine Situation zu konstruieren , wo die NCI Spalten von einer Version der Reihe , aber die CI aus einer anderen Version waren. Zusätzlich würden Off-Row-Daten und Lob-Seiten nicht durch den Latch auf der Datenseite geschützt.
Martin Smith
1
@ Martin: Einverstanden, ich habe gesehen, wie ein Self-Join nolockseine ursprüngliche Zeile nicht gefunden hat. Ein einzelner Lesevorgang eines Feldes oder einer Zeile sollte jedoch konsistent sein.
Andomar
1
@Andomar, es sei denn, die Spalten in der Zeile umfassen mehrere Seiten. Siehe meinen Link.
2
Dies sollte wirklich CW sein, da die ursprüngliche Antwort bei weitem nicht richtig war. Michael lieferte den Kern der aktuellen Antwort. Ihr Kommentar gegen die Frage stimmt immer noch nicht mit der bearbeiteten Antwort überein.