Teilweise aktualisierte Zeile lesen?

15

Angenommen, ich habe zwei Abfragen, die in zwei separaten Sitzungen in SSMS ausgeführt werden:

Erste Sitzung:

UPDATE Person
SET Name='Jonny', Surname='Cage'
WHERE Id=42

Zweite Sitzung:

SELECT Name, Surname
FROM Person WITH(NOLOCK)
WHERE Id > 30

Ist es möglich, dass die SELECTAnweisung eine halb aktualisierte Zeile liest, zum Beispiel eine mit Name = 'Jonny'und Surname = 'Goody'?

Abfragen werden fast gleichzeitig in separaten Sitzungen ausgeführt.

Tesh
quelle

Antworten:

22

Ja, SQL Server kann unter bestimmten Umständen den Wert einer Spalte aus der "alten" Version der Zeile und den Wert einer anderen Spalte aus der "neuen" Version der Zeile lesen.

Installieren:

CREATE TABLE Person
  (
     Id      INT PRIMARY KEY,
     Name    VARCHAR(100),
     Surname VARCHAR(100)
  );

CREATE INDEX ix_Name
  ON Person(Name);

CREATE INDEX ix_Surname
  ON Person(Surname);

INSERT INTO Person
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID),
                   'Jonny1',
                   'Jonny1'
FROM   master..spt_values v1,
       master..spt_values v2 

Führen Sie in der ersten Verbindung Folgendes aus:

WHILE ( 1 = 1 )
  BEGIN
      UPDATE Person
      SET    Name = 'Jonny2',
             Surname = 'Jonny2'

      UPDATE Person
      SET    Name = 'Jonny1',
             Surname = 'Jonny1'
  END 

Führen Sie in der zweiten Verbindung Folgendes aus:

DECLARE @Person TABLE (
  Id      INT PRIMARY KEY,
  Name    VARCHAR(100),
  Surname VARCHAR(100));

SELECT 'Setting intial Rowcount'
WHERE  1 = 0

WHILE @@ROWCOUNT = 0
  INSERT INTO @Person
  SELECT Id,
         Name,
         Surname
  FROM   Person WITH(NOLOCK, INDEX = ix_Name, INDEX = ix_Surname)
  WHERE  Id > 30
         AND Name <> Surname

SELECT *
FROM   @Person 

Nach ca. 30 Sekunden bekomme ich:

Bildbeschreibung hier eingeben

Die SELECTAbfrage ruft die Spalten aus den nicht gruppierten Indizes und nicht aus dem gruppierten Index ab (obwohl dies auf die Hinweise zurückzuführen ist).

Bildbeschreibung hier eingeben

Die Update-Anweisung erhält einen umfangreichen Update-Plan ...

Bildbeschreibung hier eingeben

... und aktualisiert die Indizes der Reihe nach, sodass die Werte "vor" von einem Index und "nach" von dem anderen gelesen werden können.

Es ist auch möglich, zwei verschiedene Versionen desselben Spaltenwerts abzurufen.

Führen Sie in der ersten Verbindung Folgendes aus:

DECLARE @A VARCHAR(MAX) = 'A';
DECLARE @B VARCHAR(MAX) = 'B';

SELECT @A = REPLICATE(@A, 200000),
       @B = REPLICATE(@B, 200000);

CREATE TABLE T
  (
     V VARCHAR(MAX) NULL
  );

INSERT INTO T
VALUES     (@B);

WHILE 1 = 1
  BEGIN
      UPDATE T
      SET    V = @A;

      UPDATE T
      SET    V = @B;
  END   

Führen Sie im zweiten Schritt Folgendes aus:

SELECT 'Setting intial Rowcount'
WHERE  1 = 0;

WHILE @@ROWCOUNT = 0
  SELECT LEFT(V, 10)  AS Left10,
         RIGHT(V, 10) AS Right10
  FROM   T WITH (NOLOCK)
  WHERE  LEFT(V, 10) <> RIGHT(V, 10);

DROP TABLE T;

Dies ergab auf Anhieb das folgende Ergebnis für mich

+------------+------------+
|   Left10   |  Right10   |
+------------+------------+
| BBBBBBBBBB | AAAAAAAAAA |
+------------+------------+
Martin Smith
quelle
1
Habe ich recht, dass, wenn ich eine Tabelle CREATE TABLE Person (ID INT PRIMARY KEY, Name VARCHAR (100), Nachname VARCHAR (100)) (ohne Indexe für Vor- und Nachname) und zwei Abfragen wie in der Frage habe, die ausgeführt werden in getrennten Sessions bekomme ich dann eine aktualisierte Zeile oder eine alte Zeile, aber keine Zwischenergebnisse der Aktualisierung der Zeile?
Tesh
@Tesh Ja, ich glaube nicht, dass es möglich wäre, ein anderes Ergebnis zu erzielen, da sich alle auf derselben Seite befinden und während des Schreibvorgangs durch einen Zwischenspeicher geschützt sind.
Martin Smith
Alles, was Sie mit einem WITH (NLOCK)Hinweis unerwartet bekommen, ist Ihre eigene Schuld. Kann das ohne einen NOLOCKHinweis passieren ?
Ross Presser
2
@ RossPresser - Ja, das erste Beispiel finden Sie hier im Abschnitt über die Indexkreuzung . Blogs.msdn.com/b/craigfr/archive/2007/05/02/… . Für das zweite könnte es wahrscheinlich sein, dass zwei verschiedene, festgeschriebene Versionen verfügbar sind. Ich bin nicht sicher, ob es möglich wäre, in der Praxis zu konstruieren.
Martin Smith