¿Alguien puede explicar por qué seleccionar con Nolock consultará una poción de datos actualizados?

dba.stackexchange https://dba.stackexchange.com/questions/11571

  •  16-10-2019
  •  | 
  •  

Pregunta

Estaba leyendo la respuesta de aquí (Desde StackOverflow, creo que debería preguntar aquí)

Nolock significa no colocar cerraduras en absoluto.

Su consulta puede devolver porciones de datos a partir de la actualización y las porciones antes de la actualización en una sola consulta.

Entiendo que Nolock no colocará cerraduras en la mesa, para que otras personas puedan consultar al mismo tiempo.

De la respuesta y el ejemplo que muestra, obtiene datos mientras los datos se están actualizando.

¿Por qué sucede eso?

Supongo que para Select Normal Select intentará el bloqueo de lugar en la tabla, por lo que cuando se ejecuta la declaración de actualización, coloca un bloqueo en la fila o la página. Luego, cuando intento ejecutar la instrucción SELECT, no puede colocar el bloqueo hasta que se publique el bloqueo de la instrucción de actualización.

Pero en este caso porque la instrucción SELECT no intenta poner bloqueo en la mesa, por lo que puede ejecutarse sin esperar la declaración de actualización de la instrucción.

¿Fue útil?

Solución

No es del todo cierto que NOLOCK significa colocar sin bloqueos en absoluto. Las consultas bajo esta pista seguirán tomando Sch-S cerraduras y (posiblemente HOBT Cerraduras).

Por debajo read committed Nivel de aislamiento SQL Server Will (normalmente) Tome el nivel de fila S bloquea y suelte tan pronto como se lean los datos. Estos son incompatibles con el X Locks se mantuvo en actualizaciones no comunicadas y, por lo tanto, evitan las lecturas sucias.

En el ejemplo en la respuesta vinculada el SELECT La consulta no se bloquea cuando encuentra una fila modificada, por lo que es muy probable leer actualizaciones parciales.

También puede suceder al valor predeterminado read committed nivel de aislamiento también que un SELECT Lee algunas filas con el valor "antes" y otras con el valor "después". Solo es necesario diseñar una situación en la que

  1. Seleccionar la consulta lee el valor de la fila R1 y libera su S cerrar
  2. Actualizar actualizaciones de consultas R2 y toma un X cerrar
  3. Seleccione la consulta intenta leer R2 y está bloqueado.
  4. Actualizar actualizaciones de consultas R1 y toma un X cerrar.
  5. Actualizar la transacción compromisos de así liberar sus bloqueos y permitir que la selección lea R2

Este tipo de situación podría surgir, por ejemplo, si el SELECT y UPDATE están utilizando diferentes índices para ubicar las filas de interés.

Ejemplo

CREATE TABLE T
(
X INT IDENTITY PRIMARY KEY,
Y AS -X UNIQUE,
Name varchar(10),
Filler char(4000) DEFAULT 'X'
)


INSERT INTO T (Name)
SELECT TOP 2500 'A'
FROM master..spt_values

Ahora en una ventana de consulta ejecutar

DECLARE @Sum int

SELECT 'SET @@ROWCOUNT' WHERE 1=0

WHILE (@@ROWCOUNT = 0)
SELECT @Sum = SUM(LEN(Name))
FROM T 
WHERE Y IN (-1, -2500)
HAVING SUM(LEN(Name)) = 3

Esto se ejecutará en un bucle infinito. En otra carrera

UPDATE T 
SET Name=CASE WHEN Name = 'A' THEN 'AA' ELSE 'A' END

Esto probablemente detendrá el bucle en la otra consulta (intente nuevamente si no), lo que significa que debe haber leído tampoco A,AA o AA,A

Otros consejos

La pista NOLOCK es equivalente al nivel de aislamiento de transacciones READ UNCOMMITTED, solo restringido al alcance de un método de acceso a la tabla.

¿Qué RU eso hace que el no contratado aparezca en su conjunto de resultados? Hmm, en realidad es una cuestión de "lo que no hace. Lo explicaré a continuación.

Bueno (esta es una simplificación bruta, lo sé) MSSQL (en su 'comportamiento predeterminado) es un motor de bloqueo, lo que significa que usa bloqueo para leer/escribir datos de manera consistente. En esta explicación simplificada, MSSQL usa dos tipos de cerraduras: bloqueo compartido y bloqueo exclusivo.

Un bloqueo (s) compartido es un bloqueo que permite que se lea un recurso (que puede ser una fila, página de filas o incluso una tabla completa), pero no permite una escritura. Entonces, si la transacción T1 pone un bloqueo S en la fila R1, todas las transacciones que intentan leer R1 obtendrán esa lectura, pero mientras el bloqueo S está vivo, nadie puede escribir en R1.

Un bloqueo exclusivo (x) es la contraparte del bloqueo compartido. Permite el acceso exclusivo a un recurso: ninguna otra transacción puede leer o escribir, excepto la que obtuvo el bloqueo X. En el ejemplo anterior, si T1 no tiene un bloqueo S sino un bloqueo X en R1, Nadie excepto T1 puede leerlo o escribirlo.

Ese es el Teory. Los niveles de aislamiento honran las cerraduras y respetan su prevalencia y características. Todo excepto READ UNCOMMITTED. Simple da un * (pon tu palabra de boca mala de tu preferencia aquí) a las cerraduras con respecto a la lectura; aún no puedes actualizar la fila, otra transacción obtuvo un bloqueo X. Simplemente dice: "Leeré todo lo que sea relevante para el plan de consulta: ignore qué bloqueos hay en él".Y hazlo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a dba.stackexchange
scroll top