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:
Die SELECT
Abfrage ruft die Spalten aus den nicht gruppierten Indizes und nicht aus dem gruppierten Index ab (obwohl dies auf die Hinweise zurückzuführen ist).
Die Update-Anweisung erhält einen umfangreichen Update-Plan ...
... 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 |
+------------+------------+