¿Alguien puede explicar por qué seleccionar con Nolock consultará una poción de datos actualizados?
-
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.
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
- Seleccionar la consulta lee el valor de la fila
R1
y libera suS
cerrar - Actualizar actualizaciones de consultas
R2
y toma unX
cerrar - Seleccione la consulta intenta leer
R2
y está bloqueado. - Actualizar actualizaciones de consultas
R1
y toma unX
cerrar. - 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.