Un ejemplo de transacciones mal administradas

Deja un comentario

En Firebird es extremadamente importante tener un buen manejo de las transacciones porque eso nos asegura que nuestra Base de Datos se encuentre en perfecto estado de salud.

Cuando no es así, se degrada el rendimiento porque el tamaño de la Base de Datos es mayor del que debería ser ya que está teniendo mucha basura dentro de ella y eso afecta a la velocidad con la cual se realizan las operaciones (SELECT, INSERT, UPDATE, DELETE, FETCH).

En este artículo habíamos visto el significado de los identificadores de las transacciones:

https://firebird21.wordpress.com/2013/09/08/entendiendo-los-identificadores-de-las-transacciones/

Podemos ver los valores actuales de esos identificadores usando el programa GSTAT y la opción -h, ejemplo:

C:\Archivos de Programa\Firebird\Firebird_2_5\bin>GSTAT -h MiBaseDatos

TRANSA01

Captura 1. Si haces clic en la imagen la verás más grande

En la Captura 1 tenemos un ejemplo de una Base de Datos muy bien administrada porque la diferencia entre los valores de Oldest transaction Oldest active Oldest snapshot es de 1 y la diferencia entre Oldest activeNext transaction también es de 1. Esa es la menor diferencia que podemos tener y nos indica que las transacciones de esta Base de Datos se encuentran en perfecto estado. Pero esa diferencia de 1 solamente podemos tenerla cuando nadie está usando la Base de Datos ya que mientras está en uso la diferencia casi siempre será mayor que 1 pero nunca debería ser más que 10 multiplicado por el número de usuarios. Es decir que si hay 16 personas usando la Base de Datos una diferencia mayor que 160 implicaría que algunas transacciones continúan activas cuando no deberían estarlo.

Aquí hay otro ejemplo:

TRANSA02

Captura 2. Si haces clic en la imagen la verás más grande

En la Captura 2 descubrimos que hay una diferencia significativa entre la OAT (Oldest Active Transaction) y Next transaction y nadie está usando la Base de Datos en este momento ¿Qué significa eso? que la transacción 3999 no finalizó ni con un COMMIT ni con un ROLLBACK, es por lo tanto una transacción “colgada” y debe ser corregida porque de no hacerlo se irá acumulando basura. En Oldest snapshot tenemos el número de la transacción más antigua cuya basura no puede ser recolectada automáticamente. O sea que toda la basura que dejaron las transacciones 3999 a 4196 no puede ser recolectada. Evidentemente cuanto mayor sea la diferencia entre Next transaction y Oldest snapshot mayor será el problema que tendremos con la basura.

La solución aquí es ejecutar un sweep manualmente, así:

GFIX -sweep -user SYSDBA -password masterkey MiBaseDatos

Al finalizar la ejecución de ese programa volvemos a verificar las estadísticas de la Base de Datos y esto es lo que obtenemos:

TRANSA03

Captura 3. Si haces clic en la imagen la verás más grande

¡¡¡Perfecto!!! Ahora sí la Base de Datos está sin basura y con los valores de los identificadores de las transacciones correctos.

Ejemplo de transacciones mal administradas

El motivo de escribir este artículo es que ví en Internet un mensaje de alguien pidiendo ayuda porque el sweep no le funcionaba. Los valores de los identificadores de sus transacciones eran los siguientes:

Oldest transaction  371932
Oldest active      1906983
Oldest snapshot    1906983
Next transaction   2696106

¿Qué podemos deducir mirando esos números?

  1. La transacción 371932 no finalizó con un COMMIT
  2. La transacción 1906983 no finalizó ni con un COMMIT ni con un ROLLBACK
  3. No se puede recolectar la basura que dejaron las transacciones 1906983 a 2696105
  4. Como la diferencia entre la Oldest active y la Next transaction es muy grande entonces es seguro que la aplicación que creó la transacción Oldest active (Contabilidad, Facturación, Ventas, Sueldos, etc.) ya se olvidó totalmente de ella y jamás le hará ni un COMMIT ni un ROLLBACK. Eso implica que hay que revisar la aplicación para descubrir por qué dejó una transacción activa y corregir ese problema (todas las transacciones deberían finalizar con un COMMIT o con un ROLLBACK, aún las que solamente hacen un SELECT)
  5. El sweep (barrido) solamente afectará a las transacciones del 1 al 371931. Toda la basura dejada por las transacciones 371932 a 2696105 no podrá ser eliminada ¿por qué no? porque si se la eliminara entonces la transacción 1906983 ya no tendría una visión estable de la Base de Datos
  6. Por lo tanto, la solución es buscar a la transacción 371932 y eliminarla. Y luego volver a intentar el sweep.
  7. Si el problema continúa entonces repetir el paso 6. para las siguientes Oldest transaction cuyos valores sean menores que Oldest active.

NOTA: Como la transacción 371932 no finalizó con un COMMIT entonces eliminarla no afectará al contenido de las tablas que tengamos en nuestra Base de Datos ya que el contenido de las tablas solamente es afectado por las transacciones que finalizan con un COMMIT.

Conclusión:

Periódicamente (una vez al día, una vez a la semana, una vez al mes, dependiendo de la cantidad de transacciones que tiene tu Base de Datos) deberías verificarla para comprobar que se encuentra en perfecto estado, de no ser así deberías tomar las medidas adecuadas para que lo esté.

Artículos relacionados:

Entendiendo los identificadores de las transacciones

Entendiendo sweep y garbage collection

El índice del blog Firebird21

Anuncios

Evitando conflictos cuando las transacciones superan el límite

1 comentario

Todas las transacciones tienen un número que las identifica, a ese número se le llama TID (Transaction Identificator).

TID es un número de tipo INTEGER, y los números de tipo INTEGER van desde el 0 hasta el 2 ^ 31 – 1, es decir desde 0 hasta 2.147.483.647

¿Y qué sucede cuándo se alcanzó el límite?

Si el número de tu última transacción es 2.147.483.647 el número de la siguiente transacción será 1, la cuenta se reinicia.

¿Y eso puede causar problemas?

Sí, porque habrá dos transacciones con el mismo TID, o sea que tendrás dos transacciones cuyo TID es 1. Y eso solamente puede provocar corrupción en tu Base de Datos.

¿Y cuál es la solución?

Hacer un ciclo backup/restore usando el programa GBAK antes de alcanzar el límite. Por ejemplo cuando el TID es 2.100.000.000 haces un ciclo backup/restore con GBAK y con eso conseguirás que en la Base de Datos restaurada (no en la original, sino en la que restauraste) se eliminen los TID de todas las transacciones. Por lo tanto:

  • Antes de que el número de la Next Transaction (siguiente transacción) llegue a 2.147.483.647 haces un backup de tu Base de Datos, usando para hacer el backup el programa GBAK
  • Restauras ese backup (probablemente con el mismo nombre que la Base de Datos original)
  • A partir de este momento todas las conexiones deben realizarse en la Base de Datos restaurada, no en la Base de Datos original
  • Eso te permitirá tener otras 2.147.483.647 transacciones

Ejemplo:

  1. Cuando el número de la Next Transaction llega a 2.100.000.000 se hace un backup, usando para ello el programa GBAK
  2. Se restaura el backup
  3. A partir de este momento todas las conexiones se hacen en el backup restaurado
  4. Se vuelve al punto 1.

De esta manera no habrá límites a la cantidad de transacciones totales de tu Base de Datos.

¿Por qué hay que usar GBAK para hacer el backup?

Porque GBAK además de hacer el backup también recolecta la basura (es la opción por defecto, y por supuesto que debe estar habilitada).

¿Qué significa “recolectar la basura”?

Eliminar permanentemente de la Base de Datos versiones de registros que ya no son útiles pero que permanecían en la Base de Datos, ocupando lugar innecesariamente. Cuando se hace un UPDATE o un DELETE el Firebird guarda la versión anterior del registro para que si la transacción finaliza con un ROLLBACK poder regresar a esa versión anterior. Eso va dejando versiones de registros inservibles a los cuales se les llama “basura”, alguna de la cual puede ser eliminada automáticamente, pero no toda. Para asegurarte de que toda la basura sea eliminada debes hacer un sweep (barrido) manual o usar el programa GBAK.

¿Por qué al recolectarse la basura se eliminan los TID?

Porque como hemos visto en este artículo:

https://firebird21.wordpress.com/2013/09/08/entendiendo-los-identificadores-de-las-transacciones/

una transacción solamente le interesa al Firebird cuando está activa, está revertida o está en limbo. Una transacción que finalizó con un COMMIT (o que finalizó con un ROLLBACK pero la basura que dejó ya fue recolectada) no es de interés para el Firebird ni para alguien más. ¿Por qué no? porque ya nada queda por hacer en esa transacción. Una transacción es algo transitorio, algo temporal, después de finalizar con un COMMIT o después que su basura fue recolectada ya no es interesante, porque ya nada se puede hacer en ella. Por ese motivo los TID pueden reutilizarse, pero para que puedan ser reutilizados se debe hacer un backup con GBAK y luego usar la Base de Datos restaurada, no la original.

¿Y cómo puedo saber si el número de la Next Transaction está cerca del límite de 2.147.483.647?

Usando el programa GSTAT que viene incluido con el Firebird (o muchos otros programas de terceros que también te muestran ese dato)

Transacciones1

Captura 1. Si haces clic en la imagen la verás más grande

También podrías escribir:

SELECT
   MON$NEXT_TRANSACTION
FROM
   MON$DATABASE

Entonces, cuando el número de la Next Transaction supera los 2.100.000.000 (algo que puede tardar muchos años, dependiendo de la cantidad de transacciones diarias que tenga tu Base de Datos) urgentemente debes ir pensando en hacer un ciclo backup/restore.

Si por ejemplo tienes 1.000.000 de transacciones por día entonces recién en 2.100 días necesitarás realizar el ciclo backup/restore, y eso equivale a más de 5 años y medio.

Artículos relacionados:

La arquitectura MGA

Entendiendo los identificadores de las transacciones

El índice del blog Firebird21

Entendiendo los identificadores de las transacciones

3 comentarios

Cada transacción tiene un número que la identifica de forma exacta, no pueden existir dos transacciones con el mismo número y en el mismo momento.

Identificador de la transacción

Al número que identifica a la transacción se le conoce como TID (Transaction Identificator)

Estados de las transacciones

Una transacción solamente puede estar en uno de estos estados:

  • Confirmada. Significa que la transacción finalizó con un COMMIT
  • Revertida. Significa que la transacción finalizó con un ROLLBACK
  • Activa. Significa que la transacción aún no finalizó ni con un COMMIT ni con un ROLLBACK ni está en limbo
  • Limbo. Significa que falló el segundo COMMIT. En transacciones que involucran a dos bases de datos hay que hacer dos COMMIT, uno para cada Base de Datos. Si el primer COMMIT finalizó exitosamente y el segundo COMMIT falló entonces la transacción está en limbo.

Transacciones interesantes

Hay algunas transacciones que para el Firebird son de interés, y son las siguientes:

  • Oldest transaction (la transacción más antigua). Es la transacción más antigua que no finalizó con un COMMIT. Eso significa que puede estar revertida, activa o en limbo. Las transacciones confirmadas (o sea, las que finalizaron con un COMMIT) ya no le interesan al Firebird. ¿Por qué no? porque ya han sido guardadas exitosamente y ya nada le queda para hacer con ellas. A la Oldest transaction se la conoce también como la Oldest Interesting Transaction (la más antigua transacción interesante) y se la representa con las letras OIT.
  • Oldest active transaction (la transacción activa más antigua). Es la más antigua transacción que no finalizó ni con un COMMIT ni con un ROLLBACK y no está en limbo. Eso significa que el usuario en este momento tiene a la transacción abierta y está haciendo algo con ella (insertando, modificando, borrando, consultando, ejecutando un stored procedure). Se la representa con las letras OAT.
  • Oldest snapshot transaction  (la transacción instantánea más antigua). Es la transacción más antigua cuya basura no puede ser recolectada. Una transacción deja basura cuando modifica una fila, borra una fila, o finaliza con un ROLLBACK. Lo normal es que esa basura pueda ser recolectada y entonces este número es igual al de la OAT, ese es el caso más común. A la Oldest snapshot transaction se la representa con las letras OST.
  • Next transaction (siguiente transacción). Es el número que tendrá la siguiente transacción.

Barrido automático

El sweep (barrido, de barrer con una escoba) puede estar activado o desactivado. Si está activado entonces empieza cuando la diferencia entre la OST y la OIT es mayor que el sweep interval (intervalo del barrido). Por ejemplo:

OST = 45.201

OIT = 25.200

Sweep interval = 20.000

OST – OIT = 45.201 – 25.200 = 20.001

Como el resultado de OST – OIT (que en este ejemplo es 20.001) es mayor que el intervalo del sweep (que en este ejemplo es 20.000) entonces empieza el sweep.

¿Que hace el sweep?

Elimina permanentemente de la Base de Datos toda la basura que fueron dejando las transacciones. Una transacción deja basura cuando modifica una fila, borra una fila, o finaliza con un ROLLBACK.

¿Es beneficioso el sweep?

Sí, muy beneficioso porque cuando finaliza la Base de Datos queda más limpia y en consecuencia conectarse a ella será más rápido y realizar operaciones en ella (INSERT, UPDATE, DELETE, FETCH, SELECT, EXECUTE PROCEDURE) también será más rápido.

Detectando problemas

Si la diferencia entre la OAT y la Next Transaction aumenta y aumenta eso significa que alguna transacción no está terminando con un COMMIT y por lo tanto está aumentando la cantidad de basura. Cuando la diferencia entre la OAT y la Next Transaction sea grande (“diferencia grande” depende de tu hardware y de tu software) notarás que cada vez toma más tiempo conectarse a la Base de Datos y realizar operaciones en ella. En estos casos lo correcto es utilizar el programa GFIX.EXE para hacer un sweep manual.

Reinicio de los identificadores de las transacciones. Caso 1

Cada vez que haces un ciclo backup/restore los números de los identificadores de las transacciones vuelven a empezar en uno. Por ejemplo:

NT = 65.920

Se hace un ciclo backup/restore y en la Base de Datos restaurada se ve que:

NT= 387

¿Qué pasó, por qué disminuyó la NT? Porque a todas las transacciones confirmadas el Firebird les asignó un número (el mismo número les asignó a todas las transacciones confirmadas) y a la basura la eliminó, o sea que dejó en la Base de Datos solamente las transacciones que previamente habían finalizado con un COMMIT.

¿Qué implica que los números de las transacciones interesantes cambien después de un ciclo backup/restore?

Que jamás deberías usar esos números dentro de tu programa para identificar a las transacciones entre una conexión y otra. O sea que tus programas no deberían depender de los números de las transacciones entre dos conexiones distintas. Dentro de la misma conexión no hay problema, el identificador no cambiará. Por ejemplo, una transacción está haciendo un INSERT en la tabla PRODUCTOS y esa transacción tiene el número 527. Puedes usar ese número 527 para identificarla sin problema. Pero si el usuario se desconectó de la Base de Datos y volvió a conectarse ya no deberías usar el número 527 porque ahora la transacción que hizo el INSERT a la tabla PRODUCTOS podría tener otro número (si se hizo un ciclo backup/restore entre ambas conexiones).

Reinicio de los identificadores de las transacciones. Caso 2

Hay otro caso en el cual el número de la Next Transaction no aumenta.

Los identificadores de las transacciones se guardan internamente como números de tipo INTEGER. Los números de tipo INTEGER pueden, como máximo, llegar hasta 2.147.483.647.

Entonces, ¿qué pasa cuando la Next Transaction alcanza a ese número?

Que ya no se puede seguir usando esa Base de Datos. Imposible. La conexión siempre será denegada.

¿Y cuál es la solución?

Hacer un ciclo backup/restore y usar la Base de Datos restaurada. No la original, porque la original ya está inaccesible, sino la restaurada.

Por lo tanto, si por algún motivo te interesa poder seguir accediendo a la Base de Datos original entonces el ciclo backup/restore que la reemplazará deberías hacerlo bastante antes de llegar al límite de 2.147.483.647 transacciones, por ejemplo al llegar a las 2.147.000.000 de transacciones podrías hacer un ciclo backup/restore y desde ese momento empezar a usar la Base de Datos restaurada, no la original. A la original podrás acceder un máximo de 483.647 veces más, cuando sea estrictamente necesario.

Artículos relacionados:

La Next Transaction después de un ciclo backup/restore

El índice del blog Firebird21

El foro del blog Firebird21