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.