Leggi una riga parzialmente aggiornata?


15

Supponiamo che io abbia due query, in esecuzione in due sessioni separate in SSMS:

Prima sessione:

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

Seconda sessione:

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

È possibile che l' SELECTistruzione possa leggere una riga semi-aggiornata, ad esempio una con Name = 'Jonny'e Surname = 'Goody'?

Le query vengono eseguite quasi contemporaneamente in sessioni separate.

Risposte:


22

Sì, in alcune circostanze SQL Server può leggere il valore di una colonna dalla "vecchia" versione della riga e il valore di un'altra colonna dalla "nuova" versione della riga.

Impostare:

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 

Nella prima connessione, esegui questo:

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

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

Nella seconda connessione, esegui questo:

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 

Dopo aver eseguito per circa 30 secondi ottengo:

inserisci qui la descrizione dell'immagine

La SELECTquery sta recuperando le colonne dagli indici non cluster anziché dall'indice cluster (anche se a causa dei suggerimenti).

inserisci qui la descrizione dell'immagine

La dichiarazione di aggiornamento ottiene un ampio piano di aggiornamento ...

inserisci qui la descrizione dell'immagine

... e aggiorna gli indici in sequenza in modo che sia possibile leggere i valori "prima" da un indice e "dopo" dall'altro.

È anche possibile recuperare due diverse versioni dello stesso valore di colonna.

Nella prima connessione, esegui questo:

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   

E poi nel secondo, esegui questo:

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;

Immediatamente, questo ha restituito il seguente risultato per me

+------------+------------+
|   Left10   |  Right10   |
+------------+------------+
| BBBBBBBBBB | AAAAAAAAAA |
+------------+------------+

1
Ho ragione se ho una tabella CREATE TABLE Person (ID INT PRIMARY KEY, Nome VARCHAR (100), Cognome VARCHAR (100)) (senza alcun indice su Nome e Cognome) e due query come nella domanda, che vengono eseguite in sessioni separate, quindi otterrò una riga aggiornata o una riga precedente, ma non un risultato intermedio dell'aggiornamento della riga?
— Tesh,

@Tesh sì, non penso che sarebbe possibile ottenere altri risultati poiché sarebbero tutti sulla stessa pagina e protetti da un fermo durante la scrittura.
— Martin Smith,

Qualunque cosa inaspettata che ricevi con un WITH (NLOCK)suggerimento è colpa tua. Questo può succedere senza un NOLOCKsuggerimento?
— Ross Presser,

2
@RossPresser - Sì, al primo esempio, vedere l'indice intersezione qui blogs.msdn.com/b/craigfr/archive/2007/05/02/… . Per la seconda suppongo che potenzialmente potrebbe essere disponibile se fossero disponibili due diverse versioni di commit. Non sono sicuro che sarebbe possibile progettare in pratica.
— Martin Smith,
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.