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: , , , ,

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:

  1. Gestión de transacciones en SQL Server (1/7)
  2. Gestión de bloqueos en SQL Server (2/7)
  3. Enfoques de control de transacciones en SQL Server (3/7)
  4. Enfoque optimista de gestión de transacciones en SQL Server (4/7)
  5. Enfoque pesimista de gestión de transacciones en SQL Server (5/7)
  6. Enfoque mixto de gestión de transacciones en SQL Server (6/7)
  7. Interbloqueos en SQL Server (7/7)

Más sobre: Documentación, SQL Server | Tags: , , , ,