2009-06-25 11 views
7

Soy parte de un equipo que está creando un sitio web basado en ADO.NET. A veces tenemos varios desarrolladores y una herramienta de prueba automatizada que trabaja simultáneamente una copia de desarrollo de la base de datos.Usando IsolationLevel.Snapshot pero DB todavía está bloqueando

Utilizamos el nivel de aislamiento de instantáneas, que, según mi leal saber y entender, utiliza concurrencia optimista: en lugar de bloquear, espera lo mejor y lanza una excepción si intentas comprometer una transacción si las filas afectadas han sido alteradas por otra parte durante la transacción.

Para utilizar el nivel de aislamiento de instantánea que utilizamos:

ALTER DATABASE <database name> 
SET ALLOW_SNAPSHOT_ISOLATION ON; 

y en C#:

Transaction = SqlConnection.BeginTransaction(IsolationLevel.Snapshot); 

Tenga en cuenta que IsolationLevel fotografiado no es lo mismo que ReadCommitted instantánea, que también hemos intentado, pero no están usando actualmente.

Cuando uno de los desarrolladores ingresa al modo de depuración y detiene la aplicación .NET, mantendrá una conexión con una transacción activa durante la depuración. Ahora, espero que esto no sea un problema; después de todo, todas las transacciones usan el nivel de aislamiento de instantáneas, por lo que, mientras una transacción está en pausa, otras transacciones deberían poder continuar normalmente ya que la transacción detenida no contiene bloqueos. Por supuesto, cuando la transacción pausada finaliza, es probable que detecte un conflicto; pero eso es aceptable siempre y cuando otros desarrolladores y las pruebas automatizadas puedan avanzar sin obstáculos.

Sin embargo, en la práctica, cuando una persona detiene una transacción durante la depuración, todos los demás usuarios de DB que intentan acceder a las mismas filas se bloquean a pesar de usar el nivel de aislamiento de instantáneas.

¿Alguien sabe por qué ocurre esto y/o cómo puedo lograr una concurrencia verdaderamente optimista (sin bloqueo)?

La resolución (una desafortunada para mí): Remus Rusanu señaló que los escritores siempre bloquean a otros escritores; esto está respaldado por MSDN - no acaba de salir y decirlo, pero solo menciona evitar bloqueos lector-escritor. En resumen, el comportamiento que deseo no está implementado en SQL Server.

Respuesta

8

de aislamiento SNAPSHOT el nivel afecta, como todos los niveles de aislamiento, solo lee. Las escrituras todavía se están bloqueando. Si crees que lo que ves son bloques leídos, entonces debes investigar más a fondo y verificar los tipos de recursos y nombres de recursos en los que se produce el bloqueo (wait_type y wait_resource en sys.dm_exec_requests).

No aconsejaría hacer cambios de código para admitir un escenario que involucre a los desarrolladores que miran al depurador por minutos. Si crees que este escenario puede repetirse en la producción (es decir, el cliente se bloquea), entonces es una historia diferente. Para lograr lo que desea, debe minimizar las escrituras y realizar todas las escrituras al final de la transacción, en una sola llamada que se confirma antes del retorno. De esta forma, ningún cliente puede mantener bloqueados X durante mucho tiempo (no puede colgar mientras mantiene bloqueados X). En la práctica, esto es bastante difícil de lograr y requiere mucha disciplina por parte de los desarrolladores en la forma en que escriben el código de acceso a datos.

+0

Este comportamiento es poco probable en producción. Por otro lado, la versión de desarrollo es bastante importante, y estaría dispuesto a hacer cambios de código si eso facilita el desarrollo. Desafortunadamente, un estilo de bloqueo "svn-esque" (esperar lo mejor y simplemente fallar en el conflicto) no parece implementarse. La capacidad de tener transacciones complejas y de larga duración sin bloquear todas las pequeñas transacciones aún sería útil; como es el caso, utilizamos menos transacciones que sean ideales solo para evitar el bloqueo. –

+1

No hay una bala de plata. Pero si se encuentra a menudo bloqueado en escritura y escritura, debe considerar por qué ocurre esto, por qué diferentes 'solicitudes' provocan actualizaciones de los mismos datos. Tal vez pueda particionar mejor su aplicación, disminuir la probabilidad de superposición. Tal vez algunas actualizaciones se pueden diferir, poner en cola en una mesa de trabajo durante la transacción del usuario (enque/dequeue se puede hacer sin bloque, con cuidado) y luego procesadas por procesos por lotes dedicados. Además, asegúrese de que todas las transacciones solo bloqueen el mínimo necesario (sin bloqueos de página/tabla, sin escalamiento, sin escaneos inútiles de tablas). –

2

¿Ha mirado las cerraduras cuando un desarrollador detiene la transacción? Además, solo activar el nivel de aislamiento de instantáneas no tiene mucho efecto. ¿Ha establecido ALLOW_SNAPSHOT_ISOLATION ENCENDIDO?

Estos son los pasos:

ALTER DATABASE <databasename> 
SET READ_COMMITTED_SNAPSHOT ON; 
GO 

ALTER DATABASE <database name> 
SET ALLOW_SNAPSHOT_ISOLATION ON; 
GO 

Después de la base de datos se ha habilitado para el aislamiento de instantáneas, los desarrolladores y los usuarios deben solicitar entonces de que sus transacciones se ejecutan en este modo de instantánea. Esto debe hacerse antes de iniciar una transacción, ya sea por una directiva de cliente en la transacción objeto ADO.NET o dentro de su consulta de Transact-SQL mediante la siguiente declaración:

SET TRANSACTION ISOLATION LEVEL SNAPSHOT 

Raj

+0

La base de datos tiene allow_snapshot_isolation activado. De lo contrario, se produce una excepción inmediata; no puede establecer el nivel de aislamiento como instantánea cuando allow_snapshot_isolation está desactivado (es decir, establecer el nivel de aislamiento no falla silenciosamente). Actualizaré la publicación para reflejar los comandos exactos necesarios, ¡gracias! –

Cuestiones relacionadas