Enfoque optimista de gestión de transacciones en SQL Server
Sergio Alcalde | 19 de enero de 2009 | 2 comentarios
Más sobre: Documentación, SQL Server | Tags: bloqueos, concurrencia, SQL, T-SQL, transacciones
La eficiencia de una aplicación multiusuario (usuarios concurrentes de acceso a bases de datos, en nuestro caso) que trabaje contra SQL Server se ve condicionada por ciertos factores entre los que se encuentran el enfoque de control de transacciones que adoptemos.
Como se introducía en el post anterior de esta saga “Enfoques de control de transacciones en SQL Server“,existen dos enfoques básicos: enfoque optimista y enfoque pesimista. Del enfoque que seleccionemos y de lo hábiles que seamos observando ciertas sencillas reglas en cada uno de ellos dependerá la eficiencia de nuestra aplicación.
Un bloqueo optimista supone que no se va a hacer nada en el código de la aplicación que imponga explícitamente bloqueos de los recursos cuando se esté trabajando con ellos. En lugar de hacer esto, se confía en que el gestor de bases de datos (Microsoft SQL Server, por ejemplo) se encargue de hacerlo mientras el programador únicamente se debe centrar en la lógica de la aplicación.
Una vez hemos decidio que vamos a dejar que SQL Server gestione las transacciones por nosotros, y pese a que hemos descargado sobre el gestor de bases de datos en gran medida la responsaibilidad de hacer que nuestra aplicación sea eficiente, aún hay ciertas cosas que como buenos programadores debemos tener en cuenta.
Para implementar un bloqueo optimista en una aplicación sin que ésta se detenga bruscamente cuando exista un número excesivo de bloqueos en el servidor es preciso observar ciertas reglas sencillas:
- Se debe minimizar el tiempo de duración de una transacción.
- El código de la aplicación debe asegurar que las actualizaciones se realicen sobre un registro concreto, en lugar de mantener el bloqueo mientras el usuario está examinado los datos.
- Asegurar que todos los códigos de la aplicación actualizan y seleccionan tablas en el mismo orden. Esto evitará que se produzcan los bloqueos permanentes.
Bloqueo optimista utilizando “timestamp”
SQL Server proporciona un tipo especial de datos denominado “timestamp”. El valor de una columna de este tipo es generado automáticamente cada vez que se almacena una fila con “insert” o “update”. Es simplemente un contador que cambia de manera monótona con cada actualización o inserción.
El propósito, para nuestro caso en particular, del tipo de datos “timestamp” consiste en servir como número de versión para los esquemas de bloqueo optimista.
Para poder emplear un bloqueo optimista basado en este tipo de datos, deben cumplirse las siguientes dos condiciones:
- La tabla debe tener una clave primaria.
- La tabla debe tener una columna de tipo “timestamp”.
El cliente lee la fila con el valor actual de la columna de marca temporal, pero no mantiene ningún bloqueo. En algún momento posterior, cuando el cliente quiere actualizar la fila, debe asegurarse de que ningún otro cliente haya cambiado la misma fila mientras tanto (puesto que no hay bloqueos, es responsabilidad del cliente el asegurarse de que los cambios hechos por otros clientes sean preservados). El cliente prepara de una forma especial el “update”, utilizando una columna “timestamp” como marcador de versión:
update TABLA set COLUMNA_CAMBIADA = NUEVO_VALOR where COL_CLAVE_PRIMARIA = CLAVE_PRIMARIA and timestamp = NUM_VERSION_OLD
Puesto que la cláusula “where” incluye la clave primaria, sólo se verá afectada una fila como máximo. Si algún otro cliente ha cambiado la fila, la segunda parte del “where” fallará, dándose como resultado que el “update” ha actualizado cero filas, como indicación de fallo de bloqueo. El cliente puede entonces elegir entre volver a leer los datos o efectuar cualquier otro procedimiento de recuperación que se considere oportuno.
Existen varias ineficiencias asociadas a esta forma de trabajo que se expondrán en el siguiente apartado. Por ello, si se va a utilizar un enfoque optimista basado en una marca de tiempo, se recomienda que dicha marca esté basada en un tipo de datos “int”.
Bloqueo optimista utilizando “int”
La única diferencia con respecto al método anterior es que, puesto que el servidor no va a actualizar de forma automática el valor de esta columna, será el cliente el encargado de hacerlo.
La sentencia “update” tendrá la forma:
update TABLA set COLUMNA_CAMBIADA = NUEVO_VALOR, NUM_VERSION = NUM_VERSION_OLD+1 where COL_CLAVE_PRIMARIA = CLAVE_PRIMARIA and NUM_VERSION = NUM_VERSION_OLD
Las diferencias con respecto al método anterior son las siguientes:
- El tipo de datos “int” ocupa sólo cuatro bytes mientras que el tipo de datos “timestamp” ocupa ocho.
- Al utilizar el tipo de datos “int” el cliente debe añadir la actualización de la marca en las sentencias “insert” y “update”, además de incluir el tratamiento en la cláusula “where”.
- Si se usa el tipo de datos “timestamp”, después de hacer un “update” será necesario que el cliente realice un nuevo “select” para obtener la nueva marca de tiempo, si es que quiere continuar trabajando con los mismos datos.
update TABLA set COLUMNA_CAMBIADA = NUEVO_VALOR where COL_CLAVE_PRIMARIA = CLAVE_PRIMARIA and timestamp = NUM_VERSION_OLD /* Si se quiere seguir trabajando con la misma fila, será necesario conocer el nuevo valor de la columna timestamp ya que ha sido asignado automáticamente por el servidor */ select timestamp from TABLA where COL_CLAVE_PRIMARIA = CLAVE_PRIMARIA
En el caso de usar una marca basada en un tipo de datos “int”, el cliente sabe después del “update” el nuevo valor de la marca, por lo que no tendrá que realizar una consulta para seguir trabajando con los mismos datos.
update TABLA set COLUMNA_CAMBIADA = NUEVO_VALOR, NUM_VERSION = NUM_VERSION_OLD+1 where COL_CLAVE_PRIMARIA = CLAVE_PRIMARIA and NUM_VERSION = NUM_VERSION_OLD /* Aquí el cliente sabe cuál es el nuevo valor de la columna NUM_VERSION, que es el que tenía almacenado + 1 */
En la mayoría de los casos, la elección de este enfoque de control de transacciones es acertada. Sin embargo, existen ciertas situaciones donde el número de usuarios que acceden concurrentemente a la base de datos es elevado, las transacciones son largas y un largo etcétera en los que será conveniente evaluar la idoneidad de apostar por un enfoque pesimista de gestión de transacciones.
Leer más sobre:
- Gestión de transacciones en SQL Server (1/7)
- Gestión de bloqueos en SQL Server (2/7)
- Enfoques de control de transacciones en SQL Server (3/7)
- Enfoque optimista de gestión de transacciones en SQL Server (4/7)
- Enfoque pesimista de gestión de transacciones en SQL Server (5/7)
- Enfoque mixto de gestión de transacciones en SQL Server (6/7)
- Interbloqueos en SQL Server (7/7)
Más sobre: Documentación, SQL Server | Tags: bloqueos, concurrencia, SQL, T-SQL, transacciones