Writers block readers…

Una de las diferencias más notables entre SQL Server y Oracle es el comportamiento con los bloqueos y los modelos de concurrencia y niveles de aislamiento (isolation levels).

Lo que nunca nos dejará de sorprender a los acostumbrados a trabajar con Oracle es un comportamiento como este (el servidor es SQL Server 2005):

En una primera sesión abierta con SQLCMD hacemos:

1> SELECT * FROM PRUEBA01;
2> GO
id_n        c_txt
----------- --------------------------------------------------
          1 UNO
          2 DOS
          3 THREE

En una segunda sesión abierta con SQLCMD hacemos:

1> BEGIN TRANSACTION;
2>     UPDATE PRUEBA01
3>        SET C_TXT = 'TRES'
4>      WHERE ID_N = 3;
5>     WAITFOR DELAY '00:02';
6> COMMIT TRANSACTION;
7> GO
_

Y de vuelta a la primera sesión, vemos que se queda esperando hasta que la segunda sesión termine su transacción antes de poder efectuar un sencillo y simple ‘SELECT’:

1> SELECT * FROM PRUEBA01;
2> GO
_

Sólo cuando la segunda sesión libera el bloqueo (mediante el COMMIT TRANSACTION) tenemos:

1> SELECT * FROM PRUEBA01;
2> GO
id_n        c_txt
----------- --------------------------------------------------
          1 UNO
          2 DOS
          3 TRES

(3 filas afectadas)

Por otra parte, incluso los ‘readers’ pueden bloquear a los ‘writers’, por lo que es frecuente ver ‘SELECTs’ del tipo:

'SELECT * FROM PRUEBA01 WITH(NOLOCK)'

No obstante, aunque este es el comportamiento normal, SQL Server 2005 implementa dos nuevos niveles de aislamiento:

Read Committed Isolation (Statement-Level Read Consistency) Es similar al ‘READ COMMITED’ de Oracle (que es su funcionamiento por defecto). Según la documentación, se eliminan los bloqueos sobre las filas modificadas y los ‘writers’ no bloquean a los ‘readers’ y viceversa.

Snapshot Isolation (Transaction-Level Read Consistency) Esto es parecido al modo ‘READ ONLY’ de las transacciones Oracle: los datos son vistos tal y como estaban al principio de la transacción, sin tener en cuenta ninguna modificación que otros usuarios pudieran haber realizado en el transcurso de la misma.

Ambos son implementados utilizando un mecanismo de versionado (row versioning) de datos. La diferencia está en que donde Oracle utiliza los segmentos de ‘rollback’ para obtener los estados consistentes de los datos, SQL Server genera copias de las versiones de los datos en ‘TEMPDB’ y las consulta cuando lo necesita, en vez de ir al dato ‘real’. Esto hace que TEMPDB’ deba ser mucho más grande de lo habitual, con lo que se pueden encontrar problemas de rendimiento con la I/O.

Así:

1> ALTER DATABASE db01
2>    SET READ_COMMITTED_SNAPSHOT ON;
3> go
1> BEGIN TRANSACTION;
2>     UPDATE PRUEBA01
3>        SET C_TXT = 'TRES'
4>      WHERE ID_N = 3;
5>     WAITFOR DELAY '00:02';
6> COMMIT TRANSACTION;
_

Y ahora la otra sesión no espera a que termine la transacción, sino que devuelve los resultados inmediatamente y ‘a la Oracle’ (esto es, en modo ‘read commited’: tal y como están antes de producirse el ‘commit’):

1> SELECT * FROM PRUEBA01;
2> GO
id_n        c_txt
----------- --------------------------------------------------
          1 UNO
          2 DOS
          3 THREE

(3 filas afectadas)
1>

Y una vez finaliza la transacción:

1> SELECT * FROM PRUEBA01;
2> GO
id_n        c_txt
----------- --------------------------------------------------
          1 UNO
          2 DOS
          3 TRES

(3 filas afectadas)
1>

Saludos.

Carlos.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: