PostgreSQL: Acid Test

Introducción

postgresPostgreSQL es la base de datos Open Source más avanzada del mundo (al menos eso se afirma en su sitio web). Yo la uso desde hace muchos años (desde la versión 6.0) y la he visto crecer y madurar hasta ponerse a la altura de las más capaces, como por ejemplo Oracle. Con todo, y para estar realmente a la altura, debería satisfacer un conjunto básico de exigencias ampliamente conocidas con el término Prueba del Ácido (ACID Test).

La prueba del ácido es un test muy difundido en Internet y usado por profesionales para determinar la robustez y fiabilidad de un RDBMS determinado. (haz Google).

En este documento explico en qué consiste dicha prueba y analizo los resultados en relación al RDBMS PostgreSQL. Para explicar cada uno de los elementos de la definición, utilizaré como ejemplo la hipotética base de datos de una prisión.

Definición

La prueba del ácido (ACID test) se refiere a:

  • Atomicidad (Atomicity)
  • Consistencia (Consistency)
  • Invisibilidad (1)(Isolation)
  • Durabilidad (Durability)

(1)Aunque el término inglés significa aislamiento, prefiero el de invisibilidad que empieza por I y explica de forma correcta la característica.

Atomicidad

La palabra se deriva de átomo, que significa indivisible; como indivisibles son cada una de las operaciones contenidas dentro de una transacción. Una transacción es un bloque de operaciones o instrucciones dirigido a modificar una base de datos en una determinada dirección.

En realidad, lo importante aquí, es que se cumpla la regla de todo o nada. Si todas las operaciones se realizan con éxito, los resultados producidos por la transacción se guardan en la base de datos. Si alguna operación falla, todas las operaciones son deshechas (rollback), incluso aunque alguna operación haya sido realizada con éxito.

Veamos un ejemplo. Cuando una persona ingresa en prisión, lanzamos una transacción cuya misión es la de realizar una serie de operaciones: dar de alta -o actualizar- los datos del nuevo interno, asignarle un departamento, anotar el ingreso en el libro de altas del día, etc. Si todas las operaciones se realizan con éxito, la transacción de ‘Alta de interno’ se completa (commit) y los resultados se guardan finalmente en la base de datos. Si alguna falla, por ejemplo la anotación en el libro de altas, el resto de operaciones no es tenido en cuenta y ningún resultado se almacena en la BD.

Consistencia.

Una base de datos es una herramienta para modelar y registrar una realidad cambiante, por ejemplo: el complejo mundo de una prisión. Sin embargo, debe hacerlo consistentemente de acuerdo con unas reglas determinadas o restricciones de integridad definidas. La realidad modelada así, puede ir cambiando al pasar de un estado en el que cumple las reglas, a otro en el que también las cumple.

Si al ejecutar una transacción, por el motivo que sea, se incumpliera alguna de estas reglas, la transacción no se llegaría a completar. Esto garantiza que una base de datos siempre permanezca en un estado válido, es decir, consistente con las reglas. Quedará más claro con un ejemplo.

Una de las reglas de nuestra base de datos dice: ‘cualquier interno debe estar asignado, en todo momento, a un departamento de la prisión’. Para ello, hemos creado la tabla ‘int_dept’ que tiene como atributos los identificadores de interno, del departamento y la fecha del momento. Cuando un interno cambia de departamento, tan sólo necesitamos añadir una fila a la tabla ‘int_dept’ con los datos del movimiento en cuestión. Supongamos que un día, realizando un mantenimiento de la tabla ‘departamento’, borramos el ‘Depto. 5’ de la base de datos. (En el Depto. 5, se encuentran 80 internos en ese momento). Un sistema que no maneje restricciones de integridad, dejaría 80 filas de la tabla ‘int_dept’ huérfanas de departamento, incumpliendo gravemente la regla. En cambio, un sistema que sí las maneje, impedirá la acción de acuerdo con la regla de integridad referencial establecida (…ON DELETE RESTRICT). El borrado de ese (u otro) departamento jamás se producirá mientras existan internos asignados.

Invisibilidad

Los resultados de una transacción que está siendo ejecutada, son invisibles a cualquier otra transacción hasta que la primera no haya sido completada con éxito.

Nuestro sistema dispone de una página web que los empleados utilizan para consultar información en tiempo real, por ejemplo, los ingresos del día. Supongamos que Antonio ejecuta la transacción de ‘alta de interno’ (lleva un tiempo) mientras María se dispone a consultar los ingresos del día. Si la consulta de María se realiza antes de que la transacción de Antonio se complete, María no verá el nuevo ingreso que está haciendo Antonio, aunque ya se haya escrito información en alguna de las tablas.

Durabilidad

La durabilidad garantiza que los efectos resultantes de una transacción, una vez ha sido completada con éxito, permanecen en la base de datos para siempre, incluso cuando se puedan producir posteriormente fallos de cualquier clase.

Cuando un interno es puesto en libertad, la transacción llamada ‘poner en libertad interno’ tiene que hacer varias cosas como asignar el departamento ‘Libertad’, cancelar las comunicaciones que tuviera pendientes de celebración o las sanciones que pudiera encontrarse cumpliendo en ese momento. Si alguien tropezara con el cable de alimentación del servidor, desconectando éste después de haber asignado el nuevo departamento, pero antes de cancelar las comunicaciones y sanciones; la base de datos podría quedar en un estado inconsistente (al incumplir las reglas de ‘sólo internos presentes pueden comunicar’ o ‘sólo internos presentes pueden cumplir sanciones’). Sin embargo, una vez reiniciado el servidor, un sistema que lleve un registro de transacciones realizadas, advertiría rápidamente que existe una sin completar, finalizándola correctamente.

Prueba

 

Atomicidad
En PostgreSQL podemos hacer que un grupo de sentencias SQL se ejecuten dentro de una transacción, encerrándolas entre las sentencias BEGIN y COMMIT. De esta forma aseguramos que se ejecutan todas o ninguna. Si llegados a algún punto dentro de la transacción necesitamos deshacerla completamente, utilizamos ROLLBACK, en lugar de COMMIT, y todos los cambios son deshechos. Por otro lado, PostgreSQL trata cualquier sentencia aislada como si ésta se ejecutara dentro de una pequeña transacción; aunque no usemos BEGIN, cada sentencia incorpora implícitamente un BEGIN y, si culmina con éxito, un COMMIT.
Consistencia
En mayo del 2000 se liberó la versión 7.0 de PostgreSQL. Fue una versión notable que incluía, por fin, la posibilidad de manejar integridad referencial a través de claves ajenas (foreign keys). Hasta esa versión, la única forma de hacerlo era construyendo manualmente esas reglas por medio de triggers. La capacidad de escribir reglas de negocio y dotar a los datos de consistencia, se hizo más robusta y sencilla que nunca a partir de esa versión y, lo que es mejor, facilitó enormemente el trabajo del programador.
Invisibilidad
Frente a otro modelos tradicionales que controlan el acceso concurrente a los datos a través de bloqueos, PostgreSQL utiliza un modelo denominado Multiversion Concurrency Control (MVCC), según el cual, al consultar la BD, cada transacción ve una instantánea de la BD tal como era hace un cierto tiempo (una versión de la BD) y no el estado actual de la BD. Este mecanismo evita que una transacción pueda ver datos inconsistentes modificados por otra. Aislando las transacciones que operan concurrentemente en distintas sesiones, un lector no necesita esperar a un escritor; y un escritor no necesita esperar a un lector. Si quieres conocer más a fondo este modelo: PostgreSQL Transaction Isolation
Durabilidad
PostgreSQL utiliza una técnica estándar denominada WAL (Write-ahead logging, o escritura anticipada de registros) para controlar tanto la consistencia como la durabilidad de las transacciones. Brevemente explicada, consiste en que los cambios en los ficheros de datos (tablas e índices) sólo se materializan cuando existe previamente en el disco un registro en el que están anotados dichos cambios. Siguiendo este procedimiento, no es necesario enviar páginas al disco cada vez que una transacción se completa. Esta técnica no sólo mejora el rendimiento del servidor, sino que ante un fallo de la máquina, será posible recuperar la BD a partir de ese registro: cualquier cambio no aplicado a las páginas de datos en el disco será nuevamente hecho desde el log (roll-forward recovery, o REDO) mientras que los posibles cambios realizados en páginas de disco por transacciones incompletas, podrán ser deshechos manteniendo la integridad y la consistencia de los datos (roll-backward recovery, o UNDO).

Conclusiones

La prueba del ácido (Acid Test) consiste en probar una serie de características que debe reunir todo RDBMS para ser calificado de fiable. PostgreSQL cumple con la atomicidad, consistencia, invisibilidad y durabilidad por lo que, podemos afirmar que pasa felizmente la prueba.

Existen otras muchas categorías para evaluar la idoneidad de un sistema (velocidad de respuesta, conformidad con los estándares SQL, facilidad y utilidades de administración y configuración, coste total de la propiedad (TCO), calidad de la documentación, soporte técnico, etc.; sin embargo, en entornos críticos de almacenamiento de datos, la fiabilidad debe ser siempre el primer criterio a considerar.

Agradeceré todo tipo de comentarios o sugerencias que contribuyan a mejorar este artículo o me animen a escribir otros. Si te ha gustado, házmelo saber y/o recomiéndalo a tus amigos ;-).

Referencias

 

4 comentarios

  1. Hola. Soy Silvio de Argentina.
    Me estoy tomando la atribución de publicar parte de tu trabajo y un link al mismo en mi página personal, ya que me parece muy bueno.
    Estoy estará publicado correctamente en unos días.
    Espero que no sea de tu molestia.
    Saludos
    Silvio

  2. Pésima base de datos en ALTA TRANSACCIONALIDAD. Con solo cientos de miles de registros sufre.

Dejar un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *