2010-07-09 11 views
5

Los niveles de aislamiento de transacciones serializables evitan el problema de lecturas fantasmas al bloquear cualquier inserción en una tabla en una transacción que está en conflicto con cualquier instrucción seleccionada en otras transacciones. Intento entenderlo con un ejemplo, pero bloquea la inserción incluso si el filtro en la declaración de selección no está en conflicto. Agradecería cualquier explicación sobre por qué se comporta de esa manera.¿Por qué insertar bloque de instrucción TSQL cuando el nivel de aislamiento de transacción para otra transacción es serializable con filtro no conflictivo?

Tabla de secuencias de comandos

CREATE TABLE [dbo].[dummy](
    [firstname] [char](20) NULL, 
    [lastname] [char](20) NULL 
) ON [PRIMARY] 

GO 

Sesión - 1

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 
begin tran 
select * from dummy where firstname = 'abc' 

Sesión - 2

insert into dummy values('lmn', 'lmn') -- Why this blocks? 

Respuesta

9

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') 
+0

divertido, hay que cortar para extraer esta información o que está escrito en cualquier lugar de MSDN? –

+0

@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

+0

@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

0

De http://msdn.microsoft.com/en-us/library/ms173763.aspx

SERIALIZABLE especifica lo siguiente:

Las declaraciones no pueden leer datos que han sido modificados pero aún no cometidos por otras transacciones.

Ninguna otra transacción puede modificar los datos que ha leído la transacción actual hasta que se complete la transacción actual.

Según tengo entendido, su inserción se bloqueará debido a que la transacción en la que se está ejecutando su SELECT no se ha completado.

Cuestiones relacionadas