El primer problema en su escenario de prueba es que la tabla no tiene ningún índice útil en firstname
. El segundo es que la mesa está vacía.
De Key-Range Locking en BOL
antes de que ocurra alcance llave de bloqueo, las siguientes condiciones deben ser satisfechas :
El nivel de transacción aislamiento se debe establecer en SERIALIZABLE
.
El procesador de consultas debe usar un índice para implementar el predicado del filtro de rango. Por ejemplo, la cláusula WHERE
en una declaración SELECT
podría establecer una condición de rango con este predicado : ColumnX BETWEEN N'AAA' AND N'CZZ'
. Un bloqueo de rango de clave solo puede ser adquirido si ColumnX está cubierto por una clave de índice .
No existe un índice adecuado para tomar RangeS-S
cerraduras de modo de garantizar serializable la semántica de SQL Server necesita para bloquear toda la tabla.
Si intenta agregar un índice agrupado en la tabla en la columna del primer nombre como se muestra a continuación y repita el experimento ...
CREATE CLUSTERED INDEX [IX_FirstName] ON [dbo].[dummy] ([firstname] ASC)
... ¡usted seguirá bloqueado!
A pesar de que ahora existe un índice adecuado y el plan de ejecución muestra que se busca para satisfacer la consulta.
Usted puede ver por qué ejecutando el siguiente
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
SELECT *
FROM dummy
WHERE firstname = 'abc'
SELECT resource_type,
resource_description,
request_mode
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID
COMMIT
devoluciones
+---------------+----------------------+--------------+
| resource_type | resource_description | request_mode |
+---------------+----------------------+--------------+
| DATABASE | | S |
| OBJECT | | IS |
| PAGE | 1:198 | IS |
| KEY | (ffffffffffff) | RangeS-S |
+---------------+----------------------+--------------+
SQL Server no sólo se obtiene un bloqueo gama exactamente en el rango especificado en la consulta.
Para un predicado de igualdad en un índice único, si hay una clave coincidente solo tomará un bloqueo regular en lugar de cualquier tipo de bloqueo de rango.
Para un predicado de búsqueda no único, elimina bloqueos en todas las claves coincidentes dentro del rango más el "siguiente" al final del rango (o en ffffffffffff
para representar infinito si no existe la tecla "siguiente"). Even deleted "ghost" records se puede utilizar en este bloqueo de teclas de rango.
As described here de un predicado de igualdad ya sea en un único índice único o no
Si no existe la clave, entonces la cerradura de la 'gama' se toma en el 'siguiente' clave tanto para el único y no - índice único. Si la tecla 'siguiente' no existe, entonces se aplica un bloqueo de rango en el valor 'infinito'.
Así que con una mesa vacía la SELECT
todavía termina bloqueo todo el índice. También necesitaría haber insertado previamente una fila entre abc
y lmn
y luego su inserción tendría éxito.
insert into dummy values('def', 'def')
divertido, hay que cortar para extraer esta información o que está escrito en cualquier lugar de MSDN? –
@MartinSmith Supuse que sin un índice de cobertura la transacción serializable daría como resultado un bloqueo de tabla, pero no he encontrado esta información en otro lugar y no soy lo suficientemente sofisticado como para probar mi suposición. Confío en que está en lo correcto aquí ... pero quería preguntar si puede compartir una fuente para su conocimiento (documentación o pruebas personales verificadas). ¡Muchas gracias! – TCC
@MartinSmith Con respecto a mi comentario anterior, estoy seguro de que los métodos en esta pregunta podrían usarse para verificar el repliegue de "bloqueo de tabla" ... No estoy seguro de interpretarlos correctamente ya que no estoy acostumbrado a mirar Descripciones de bloqueo (pero estoy aprendiendo gracias a excelentes respuestas como esta). Agregué un enlace a esta pregunta de los documentos de MSDN porque realmente es un ejercicio sobresaliente explicar los casos límite en torno al bloqueo de rango. Gracias por su esfuerzo en la comunidad. – TCC