¿Leer una fila parcialmente actualizada?


15

Digamos que tengo dos consultas, que se ejecutan en dos sesiones separadas en SSMS:

Primera sesión:

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

Segunda sesión:

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

¿Es posible que la SELECTinstrucción pueda leer una fila medio actualizada, por ejemplo, una con Name = 'Jonny'y Surname = 'Goody'?

Las consultas se ejecutan casi simultáneamente en sesiones separadas.

Respuestas:


22

Sí, SQL Server puede, en algunas circunstancias, leer el valor de una columna de la versión "antigua" de la fila y el valor de otra columna de la versión "nueva" de la fila.

Preparar:

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 

En la primera conexión, ejecute esto:

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

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

En la segunda conexión, ejecute esto:

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 

Después de correr durante unos 30 segundos me sale:

ingrese la descripción de la imagen aquí

La SELECTconsulta está recuperando las columnas de los índices no agrupados en lugar del índice agrupado (aunque debido a las sugerencias).

ingrese la descripción de la imagen aquí

La declaración de actualización obtiene un amplio plan de actualización ...

ingrese la descripción de la imagen aquí

... y actualiza los índices en secuencia para que sea posible leer los valores "antes" de un índice y "después" del otro.

También es posible recuperar dos versiones diferentes del mismo valor de columna.

En la primera conexión, ejecute esto:

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   

Y luego en el segundo, ejecuta esto:

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;

De inmediato, esto me devolvió el siguiente resultado

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

1
Estoy en lo cierto si tengo una tabla CREAR TABLA Persona (Id INT PRIMARY KEY, Nombre VARCHAR (100), Apellido VARCHAR (100)) (sin ningún índice en Nombre y Apellido) y dos consultas como en la pregunta, que se ejecutan en sesiones separadas, obtendré una fila actualizada o una fila anterior, pero ¿no algún resultado intermedio de actualizar la fila?
Tesh

@Tesh sí, no creo que sea posible obtener ningún otro resultado, ya que todo estaría en la misma página y protegido por un pestillo durante la escritura.
Martin Smith

Cualquier cosa inesperada que obtengas con una WITH (NLOCK)pista es tu culpa. ¿Puede suceder esto sin una NOLOCKpista?
Ross Presser

2
@RossPresser - Sí al primer ejemplo, vea la pieza de intersección del índice aquí blogs.msdn.com/b/craigfr/archive/2007/05/02/… . Por el segundo, supongo que podría hacerlo si dos versiones comprometidas diferentes estuvieran disponibles. No estoy seguro de que sea posible diseñar en la práctica.
Martin Smith
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.