¿Cómo funciona una transacción SNAPSHOT?

Deja un comentario

Como recordarás, una transacción en Firebird puede tener uno de estos tres aislamientos:

  • READ COMMITED
  • SNAPSHOT
  • SNAPSHOT TABLE STABILITY

Los aislamientos le dicen al Firebird lo que debe hacer cuando una fila quiere ser actualizada (UPDATE) o borrada (DELETE) por más de una transacción al mismo tiempo.

Veamos un ejemplo:

  1. La transacción T1 empieza (su aislamiento es SNAPSHOT, y su modo de bloqueo es WAIT)
  2. La transacción T2 empieza (su aislamiento es SNAPSHOT)
  3. La transacción T2 actualiza (UPDATE) a una fila X de la tabla PRODUCTOS.
  4. La transacción T2 finaliza con un COMMIT
  5. La transacción T3 empieza (su aislamiento es SNAPSHOT)
  6. La transacción T3 también actualiza (UPDATE) a la misma fila X de la tabla PRODUCTOS
  7. La transacción T1 trata de actualizar (UPDATE) a la misma fila X de la tabla PRODUCTOS, pero como esa fila está bloqueada por la transacción T3 entonces deberá esperar hasta que la transacción T3 finalice.

Sin embargo, debemos notar que en este ejemplo la transacción T1 fallará siempre. ¿Por qué? Porque tendrá un conflicto con la transacción T3 si la transacción T3 finalizó con un COMMIT, o tendrá un conflicto con la transacción T2 si la transacción T3 finalizó con un ROLLBACK. O sea que, sin importar como termine la transacción T3 (con un COMMIT o con un ROLLBACK) la transacción T1 fallará.

Te puedes preguntar: ¿y por qué la transacción T1 debe esperar hasta que finalice la transacción T3? Después de todo, en ambos casos fallará, entonces ¿por qué la espera?

La respuesta está en que el Firebird solamente verifica la última versión de una fila para saber si ocurrió un conflicto o no. Si verificara la anteúltima versión entonces podría hacer fallar a la transacción T1 en el mismo momento en que hiciera un UPDATE, pero eso implicaría más trabajo y por lo tanto solamente verifica a la última versión.

Una transacción SNAPSHOT en el momento en que se inicia copia en su porción de la memoria RAM de la computadora la TIP (Transaction Inventory Page) conteniendo a todas las transacciones que están activas en ese momento. O sea, la transacción T2 conoce cuales son todas las transacciones que estaban activas cuando se inició la transacción T2, pero desconoce totalmente a las transacciones que se iniciaron después que ella y por lo tanto supone que están activas ya que evidentemente no habían finalizado cuando empezó la transacción T2. Cada transacción tiene un número único, que se guarda en la TIP. Cuando una transacción inicia bloquea a su propio número y lo desbloquea cuando finaliza (sea con un COMMIT o con un ROLLBACK). De esta manera es muy fácil saber si una transacción está activa o no. Si no se puede desbloquear su número, está activa. Si se puede desbloquear su número, no está activa.

Cuando una transacción SNAPSHOT trata de bloquear a una fila para hacerle un UPDATE o un DELETE, lo que puede ocurrir es lo siguiente:

  • Si la última versión de esa fila fue creada por una transacción que tiene un número menor y que no está en su copia de la TIP, el bloqueo tendrá éxito. ¿Por qué? porque como no está en su copia de la TIP y el número es menor, significa que una transacción anterior que insertó o actualizó a la fila ya finalizó con un COMMIT.
  • Si la última versión de una fila fue creada por una transacción cuyo número está en la TIP entonces debe verificar si esa transacción ya finalizó. ¿Y cómo lo verifica? Tratando de bloquear el número que esa otra transacción tiene en la TIP. Si lo consigue, la otra transacción ya finalizó y se puede bloquear a la fila con éxito.
  • Si el último COMMIT a la fila fue realizado por una transacción que tiene un número de transacción mayor, eso significa que esa otra transacción empezó después. Y por lo tanto, no se podrá bloquear a la fila.

Ejemplo:

Empieza una transacción, su número es 529, y en su copia de la TIP tiene a los números 521, 525, 526, 528. Eso significa que esas 4 transacciones están activas, aún no han finalizado ni con un COMMIT ni con un ROLLBACK.

La transacción cuyo número es 529 quiere hacer un UPDATE a una fila X de la tabla PRODUCTOS, el número de transacción que tiene la última versión de esa fila X es el 291. Como el número de transacción 291 no está en la copia de la TIP, eso significa que la transacción 291 (o una transacción anterior a ella) ya ha finalizado con un COMMIT y por lo tanto se podrá realizar el UPDATE con éxito a la fila X.

La transacción cuyo número es 529 quiere hacer un UPDATE a una fila X de la tabla PRODUCTOS, el número de transacción que tiene la última versión de esa fila es el 526. Como el número de transacción 526 está en la copia de la TIP, eso significa que la transacción 526 estaba activa cuando se inició la transacción 529. Pero ¿está activa ahora? quizás sí, quizás no, para verificarlo la transacción 529 trata de bloquear al número 526 en la TIP global, no en su propia copia de la TIP. Si consigue realizar el bloqueo, la transacción 526 ya no está activa y entonces podrá realizar el UPDATE con éxito. ¿Y si no consigue bloquear, qué hace? Eso dependerá del modo de bloqueo. Si es WAIT, seguirá intentando bloquear hasta tener éxito. Si es NO WAIT lanzará una excepción con un mensaje de error.

La transacción cuyo número es 529 quiere hacer un UPDATE a una fila X de la tabla PRODUCTOS, el número de transacción que tiene la última versión de esa fila es el 540. ¿Podrá la transacción 529 realizar el UPDATE? Depende. Si la transacción 540 finaliza con un COMMIT, no podrá. ¿Por qué no? Porque 540 es mayor que 529. Si la transacción 540 finaliza con un ROLLBACK entonces hay que buscar el número que tiene la última versión de esa fila X cuya transacción finalizó con un COMMIT. Si el último COMMIT a la fila X fue realizado por la transacción 520, la transacción 529 podrá realizar el UPDATE (porque 520 es menor que 529). Si el último COMMIT a la fila X fue realizado por la transacción 535, la transacción 529 no podrá realizar el UPDATE (porque 535 es mayor que 529).

Una transacción SNAPSHOT solamente puede actualizar (UPDATE) o borrar (DELETE) a las filas creadas por las transacciones que empezaron antes que ella.

Recuerda que el Firebird crea una nueva versión de una fila cada vez que se ejecuta el comando UPDATE o el comando DELETE en esa fila.

Sin importar como finalice la transacción (con un COMMIT o con un ROLLBACK) hay una nueva fila. Esto va creando filas inservibles (se les llama “basura”) y por ese motivo hay que limpiar a la Base de Datos de basura cada cierto tiempo.

Una fila tiene la siguiente forma:

| Nº de Transacción | Columna1 | Columna2 | Columna 3| etc.

Importante: Una transacción T1 (cuyo aislamiento es SNAPSHOT) puede actualizar (UPDATE) o borrar (DELETE) a una fila solamente cuando el Nº de Transacción que realizó el último COMMIT a esa fila es menor que el número de la transacción T1.

Artículos relacionados:

Entendiendo a las transacciones

Entendiendo a los identificadores de las transacciones

Modos de bloqueo de las transacciones

Bloqueos mortales

Lock conflict on no wait transaction. Deadlock

El índice del blog Firebird21

El foro del blog Firebird21

Anuncios

Trabajando con grandes bases de datos

4 comentarios

Los problemas con los cuales nos encontramos al trabajar con bases de datos grandes son distintos a los problemas que tienen las bases de datos pequeñas.

Como las empresas constantemente están almacenando más y más datos las tablas van creciendo de tamaño diariamente, quizás minuto a minuto. Llega un momento en que la Base de Datos ya puede considerarse “grande”.

¿Cuándo una Base de Datos es grande?

Como muchas otras cosas en Informática, ésta también depende del punto de vista. Para alguien podría ser grande y para otros pequeña, aunque en general se considera “grande” a las bases de datos que alcanzan o superan un tamaño de 10 Gigabytes. En este blog se considera que:

  • Pequeña. Es una Base de Datos con tamaño menor a 1 Gb
  • Mediana. Es una Base de Datos cuyo tamaño está entre 1 Gb y 10 Gb
  • Grande. Es una Base de Datos cuyo tamaño es mayor que 10 Gb

Normalmente, si no se almacena multimedia (archivos gráficos, de sonido, de vídeo, etc.) las bases de datos van creciendo a un ritmo bastante parejo y predecible, por ejemplo podríamos tener una que crece alrededor de 1 Megabyte por día. Desde luego que algunos días crece más y algunos días crece menos, pero siempre está por ahí cerca.

Problemas típicos con las bases de datos pequeñas

  • Consultas lentas
  • Stored procedures o triggers lentos

Soluciones típicas a esos problemas

  • Optimizar las instrucciones SQL.
  • Realizar un ciclo backup/restore con el programa GBAK

El optimizar las instrucciones SQL (principalmente las cuatro principales: INSERT, UPDATE, DELETE, SELECT) conduce a una notoria mejoría en la velocidad. Muy relacionado con esto se encuentra el correcto manejo de las transacciones. Ante alguna corrupción restaurar el backup realizado con GBAK suele ser suficiente.

Problemas típicos con las bases de datos grandes

  • No se sabe donde está el problema
  • No se sabe por qué sucede
  • Realizar un ciclo backup/restore puede ser una gran pérdida de tiempo, porque la restauración puede demorarse un día o más, y no asegura que se haya solucionado el problema

Tareas administrativas diarias en las bases de datos grandes

Si ocurre un problema, puede demorarse mucho la solución así que lo más inteligente es evitar que ocurra. Para ello:

  1. Debe realizarse un backup con GBAK todos los días
  2. Debe verificarse el rendimiento de todas las transacciones
  3. Debe verificarse que todas las instrucciones SQL estén optimizadas
  4. Debe verificarse cada índice y la estadística de cada índice
  5. Debe verificarse que la estructura de la Base de Datos sea la más conveniente
  6. Debe verificarse el archivo FIREBIRD.LOG varias veces por día

Aunque realizar un ciclo backup/restore no nos asegura que solucionaremos todos los problemas, tener una Base de Datos grande sin backups actualizados es un suicidio. En las transacciones lo más importante es que ninguna demore mucho en completarse (“mucho” es relativo, pero en general si tarda más de un minuto entonces está tardando una eternidad). Las instrucciones SQL no optimizadas hacen perder tiempo, algo que no se puede permitir en estas circunstancias. Y no debemos olvidar que una instrucción SQL que hoy está optimizada y funciona perfectamente podría dejar de estarlo dentro de unos meses cuando la Base de Datos haya aumentado mucho de tamaño. Por eso la verificación debe hacerse diariamente.

El archivo FIREBIRD.LOG es el mejor lugar para verificar que todo esté correcto, si hay algún problema casi siempre aparecerá en ese archivo.

¿Cómo realizar el ciclo backup/restore?

Es bastante frecuente, aunque erróneo, hacerlo de esta manera:

Base de Datos —> Backup con el mismo nombre anterior

Por ejemplo, la Base de Datos se llama CONTA.FDB y el archivo de backup siempre se llama CONTA.FBK, ¿cuál es el problema potencial? Que si la Base de Datos está corrupta entonces el nuevo backup no servirá y el anterior no podrá ser utilizado porque fue sobre-escrito.

Lo correcto, por lo tanto, es hacer el backup de esta manera:

Base de Datos —> Backup con un nombre distinto al anterior

Esto evidentemente implica que tendremos varios archivos de backup, pero es preferible que sobren y no que falten.

El archivo delta

Cuando se ejecuta el programa GBAK para realizar un backup, éste hace el backup de todo el contenido que tiene en ese momento la Base de Datos. Es como si le tomara una fotografía. Nada que se realice con posterioridad se guardará en el backup ni en la Base de Datos, sólo lo que existía en el momento de iniciarse GBAK. Pero ¿y qué pasa con los datos que los usuarios continúan insertando, actualizando o borrando? Que no se guardan en la Base de Datos original sino en un archivo temporario llamado delta. Cuando GBAK finaliza, entonces todo el contenido del archivo delta se copia dentro de la Base de Datos.

Cuando hacemos backup de bases de datos pequeñas no vale la pena preocuparse por ese archivo delta pero cuando es una Base de Datos grande sí, porque no podemos permitirnos que esté corrupto. Un motivo podría ser que no haya suficiente espacio en el disco duro para el archivo delta.

La restauración

Aquí, es obligatorio que al finalizar un backup se realice un restore (en otro disco duro y preferiblemente en otra computadora) para asegurarnos de que se encuentre en perfectas condiciones y pueda ser utilizado en caso de necesidad.

Nada hay peor que creer que se tiene un backup actualizado pero eso no es cierto porque el backup se encuentra inservible. No ocurre frecuentemente, pero a veces ocurre, y no se puede tomar ese riesgo.

Los índices

Los índices en Firebird se utilizan en las búsquedas y en los filtros (cláusula WHERE) y cuando deseamos que los resultados aparezcan en un cierto orden (cláusula ORDER BY)

Para saber si un índice es el adecuado, es necesario, y se encuentra en buena salud, debemos verificar sus estadísticas. En Firebird los índices pueden degradarse y no debemos permitir que tal cosa ocurra.

Acciones a tomar si se descubre un problema

Estas son recomendaciones que a veces podrían no aplicarse, dependen de cada caso, pero servirán de guía:

  1. Una transacción está demorando mucho. Detectar cual es la transacción, cual es el programa culpable, y desconectar al usuario
  2. Una consulta está demorando mucho. Verificar cual es la consulta, mirar su PLAN y si es necesario crear un nuevo índice

Programas que se pueden utilizar cuando se trabaja con grandes bases de datos

Aunque detectar los problemas y solucionarlos podría hacerse manualmente, eso requerirá que la persona encargada conozca mucho del tema y que tenga suficiente tiempo y ganas para dedicarle a esa tarea. Para estos casos se justifica adquirir software que ayude en la detección y corrección. Los recomendados son:

  • FBDataGuard. Se ejecuta en la misma computadora donde se encuentra la Base de Datos. Su principal tarea es prevenir que se corrompa. Monitorea el rendimiento, realiza el backup en la forma correcta, obtiene estadísticas, y si descubre algún problema entonces envía un e-mail describiéndolo
  • FBScanner. Verifica cada instrucción SQL que el Cliente le envía al Servidor, puede realizar un análisis detallado de cada consulta, PLAN, transacción y conexión, de esta manera sirve para detectar los “cuellos de botella”, las transacciones que se demoran mucho, los usuarios que se desconectan de mala manera, y monitorea lo que un usuario o una aplicación están realizando.
  • IBTM. Monitorea y analiza transacciones dinámicas. Obtiene los valores de OIT, OAT, OST, NT y visualiza como se van moviendo. Detecta transacciones que se demoran mucho, los momentos en que muchas transacciones se están ejecutando, los momentos en que ocurre el sweep, la basura dejada por los ROLLBACKs.
  • IBAnalyst. Analiza las estadísticas de la Base de Datos e identifica posibles problemas que causan un bajo rendimiento: transacciones que demoran mucho, cantidad de versiones de los registros, registros que han sido borrados pero aún permanecen en la Base de Datos y por lo tanto demoran la lectura, promedio de transacciones por día, conexiones perdidas, índices no usados, índices con muchos valores repetidos, etc.
  • FBMonLogger. Detecta consultas lentas, transacciones que tienen un aislamiento incorrecto, basura que debe ser recolectada, uso de la memoria, etc.
  • Sinática. Monitorea a la Base de Datos en tiempo real, ayudando a detectar los procesos que consumen muchos recursos o que producen “cuellos de botella”, además de las transacciones que demoran mucho en finalizar.

Conclusión:

Aunque realizar las tareas administrativas de backup, verificación de las estadísticas de los índices, revisar el archivo FIREBIRD.LOG, etc. deberían hacerse regularmente con cualquier Base de Datos, cuando éstas son de gran tamaño esas tareas ya son una obligación imprescindible porque no se puede correr el riesgo de que se corrompa o de que funcione muy lentamente, muchas veces tales bases de datos deben funcionar 365/24/7 (o sea, los 365 días del año, durante las 24 horas, de cada uno de los 7 días de la semana) y cualquier demora o detención puede ser muy grave.

En estos casos, suele ser recomendable contratar a una persona cuya función sea la de Administrador de la Base de Datos y proveerle de las herramientas informáticas adecuadas para que pueda realizar efectivamente su labor.

Artículos relacionados:

El índice del blog Firebird

El foro del blog Firebird21

Artículos

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

Deja un comentario

Como recordarás, al Firebird hay unas cuantas transacciones que le interesan, ellas son:

  • Oldest Transaction, representada por las letras OIT que significan Oldest Interesting Transaction
  • Oldest Active Transaction, representada por las letras OAT
  • Oldest Snapshot Transaction, representada por las letras OST
  • Next Transaction, representada por las letras NT

 Puedes leer más sobre ellas en este artículo:

Entendiendo los identificadores de las transacciones

Los números de las transacciones siempre van en aumento, hasta que se realiza un ciclo backup/restore.

¿Qué sucede cuándo se realiza un ciclo backup/restore?

 Que en la Base de Datos restaurada (no en la original, sino en la restaurada), el identificador de todas las transacciones que finalizaron con un COMMIT es puesto en 1.

¿Y por qué el número de la Next Transaction no es 2, ó 3, ó un número muy cercano a ellos?

Después de todo, podrías pensar que si todas las transacciones que finalizaron con un COMMIT tienen el identificador 1, la Next Transaction debería tener el número 2. O si el programa GBAK abre alguna transacción más, entonces un número muy cercano al 2. Pero no es así, la Next Transaction puede estar muy alejada del número 2.

La respuesta es que el programa GBAK puede abrir muchas transacciones cuando restaura una Base de Datos.

Ejemplo:

En la ventanita “Símbolo del sistema” escribimos el comando GSTAT -h para conocer los identificadores de las transacciones de una Base de Datos.

NT1

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

Se hace el ciclo backup/restore con la opción -v[erbose] y luego se ejecuta el comando GSTAT -h en la Base de Datos restaurada, obteniendo estos valores:

NT2

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

En la Captura 1. podemos ver los identificadores originales de las transacciones y en la Captura 2. podemos ver los valores de los identificadores en la Base de Datos restaurada. Y lo que llama la atención es que la Next Transaction es 304, un número aparentemente muy alto, muy alejado del 3 que uno podría esperar. ¿Por qué?

Porque el programa GBAK abre varias transacciones:

  • Al iniciar la restauración de la Base de Datos, la Next Transaction es puesta en 1
  • Luego, para restaurar los metadatos puede abrir nuevas transacciones
  • Si se usó la opción -o[nce] se iniciará una transacción por cada tabla restaurada
  • Si se usó la opción -v[erbose] se iniciará una transacción por cada índice restaurado

Entonces, ahora sí ya tiene sentido del por qué la Next Transaction está tan alejada del número 1. Es que el programa GBAK abre varias transacciones al restaurar un backup.

Fíjate en un detalle interesante. Como la Base de Datos restaurada aún no ha sido utilizada entonces no importa que los identificadores de las otras transacciones (OIT, OAT, OST) estén desfasados. En este momento nada significan y por lo tanto el número que tengan es irrelevante.

Sin embargo, si te conectas a la Base de Datos e inicias una transacción cuando te desconectes esos números sí ya estarán actualizados. Por ejemplo:

NT3

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

Aquí, usando el programa ISQL nos conectamos a la Base de Datos restaurada, salimos con un EXIT (al salir con un EXIT de ISQL se ejecuta automáticamente un COMMIT, si se sale con un QUIT entonces se ejecuta automáticamente un ROLLBACK) y volvemos a verificar los identificadores de las transacciones ¿y con qué nos encontramos?

Conque los identificadores OIT, OAT y OST se han actualizado.

Estos nuevos valores sí son los correctos. Los anteriores no tenían importancia porque aún no se había usado la Base de Datos, entonces eran irrelevantes sus valores.

Para verificar que la opción -v[erbose] realmente inicia varias transacciones se restauró la misma Base de Datos pero sin esa opción, y este fue el resultado obtenido:

NT4

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

Como puedes ver ahora la Next Transaction es solamente 84, entonces se comprobó que usando la opción -v[erbose] el programa GBAK inicia varias transacciones. Usando esa opción, Next Transaction fue 304, sin usarla fue 84. Desde luego que esos números variarán en tu caso porque dependen de la cantidad de índices que hayas definido.

Conclusión:

Al hacer un ciclo backup/restore con el programa GBAK, en la nueva Base de Datos el valor de la Next Transaction empieza con 1 pero como el programa GBAK abre varias transacciones para poder realizar sus tareas, entonces al finalizar la restauración el valor de la Next Transaction puede estar bastante alejado del 1, dependiendo de la cantidad de transacciones que el programa GBAK tuvo que abrir.

No importa cuales son los valores de los identificadores OIT, OAT, y OST al finalizar la restauración porque aún no han sido utilizados. Solamente después de finalizar la primera transacción sus valores serán actualizados y estarán muy próximos al de la Next Transaction.

Artículos relacionados:

Entendiendo los identificadores de las transacciones

El índice del blog Firebird21

El foro del blog Firebird21

Usando Trace Manager

9 comentarios

Con la versión 2.5 de Firebird se agregó algo que puede ser muy útil: Trace Manager.

¿Qué hace Trace Manager?

Nos permite conocer todas las conexiones realizadas a una Base de Datos y todas las transacciones, en tiempo real, o sea apenas ocurren.

El programa que realiza esta tarea se llama FBTRACEMGR.EXE y lo encontrarás en la carpeta \BIN\ de tu instalación del Firebird.

Tarea a realizar:

Queremos monitorear todas las actividades que realiza el Servidor del Firebird, para ello necesitaremos hacer lo siguiente:

  1. Crear un archivo de configuración donde podremos determinar, entre otras cosas:
    • Monitorear todo lo que ocurre en una conexión
    • Monitorear todas las actividades de un usuario
    • Monitorear todas las transacciones en una o varias bases de datos
  2. Ejecutar el programa FBTRACEMGR.EXE con el archivo de configuración anterior
  3. Opcionalmente (y preferiblemente) en lugar de enviar los resultados a la pantalla del monitor podemos enviarlos a un archivo de texto y de esa manera será muy fácil posteriormente revisar ese archivo de texto y conocer exactamente lo que ocurrió en la Base de Datos

Enconces, empezaremos creando con el bloc de notas del Windows un archivo de texto donde guardaremos la configuración a utilizar:

TRACE1

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

Las de arriba no son las únicas opciones posibles, hay más, en la Captura 2 las encontrarás a todas:

TRACE2

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

Ahora que ya hemos creado un archivo de configuración podemos ejecutar el programa FBTRACEMGR.EXE y empezar a monitorear todo lo que acontece dentro de la Base de Datos.

TRACE3

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

En lugar de localhost: puedes necesitar escribir la dirección IP de tu Servidor, opcionalmente seguido por una barra y el número del puerto de conexión, algo como:

192.168.0.1/3051:

Abrimos ahora otra ventana “Símbolo del sistema” y ejecutamos en ella el programa ISQL.EXE y nos conectamos a una Base de Datos para ver lo que sucede con nuestro monitoreo:

TRACE4

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

Y en la otra ventana del sistema (en la cual habíamos ejecutado el programa FBTRACEMGR.EXE) vemos esto:

TRACE5

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

“Trace session ID 3 started” nos indica que esta es la tercera sesión del TraceManager que hemos iniciado hoy.

“TRACE_INIT” nos indica que se inició el Trace.

“COMMIT_TRANSACTION” nos indica que una transacción terminó con un COMMIT.

“ATT_4979” nos indica que esta es la conexión número 4.979 a la Base de Datos desde que fue creada.

“SYSDBA” nos indica quien fue el usuario que se conectó a la Base de Datos. El “:NONE” después de su nombre nos indica que no usó un rol para conectarse. Si un usuario utiliza un rol, el nombre de ese rol aparecerá aquí.

“XNET:WALTER-PC” nos indica la forma de conexión (a través de XNET en este caso, también podría haber sido a través de una dirección IP) y el nombre de la computadora (o la dirección IP si aplica).

“C:\Archivos de programa\…” es el nombre del programa que se usó para conectarse a la Base de Datos. En este caso el nombre de ese programa fue ISQL.EXE pero lo normal es que se trate del nombre de tu aplicación (Contabilidad, Facturación, Ventas, Sueldos, etc.)

“TRA_90742” es el número de la transacción. En este caso fue la transacción número 90.742.

“CONCURRENCY | WAIT | READ_WRITE” indican los parámetros de la transacción. En este caso la transacción fue SNAPSHOT, WAIT, READ WRITE, en otros casos podría ser: READ COMMITTED, NO WAIT, READ ONLY, REC_VERSION, NO_REC_VERSION, etc.

“START_TRANSACTION” nos indica que se inició una transacción.

“EXECUTE_TRIGGER_FINISH” nos indica que finalizó la ejecución de un trigger cuyos datos vemos un poco más abajo.

Y bueno, puede mostrarte más información relacionada pero ya la puedes descubrir por tí mismo, para eso eres lo suficientemente inteligente como para entender lo que ocurre.

Si quieres que el programa FBTRACEMGR.EXE no envíe la información a la pantalla sino que la envíe a un archivo de texto le puedes redireccionar la salida con el símbolo mayor que, como se muestra a continuación:

TRACE6

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

Entonces, más tarde podrás revisar el contenido del archivo MONITOREO1.TXT (desde luego que ese nombre es un ejemplo, tú puedes elegir cualquier otro nombre).

TRACE7

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

Conclusión:

Poder “trazar” las operaciones que ocurren dentro de una Base de Datos puede resultarnos muy pero muy útil cuando vemos que hay problemas con ella, por ejemplo si hay transacciones que no terminan eso nos indica un problema con una aplicación (Contabilidad, Facturación, Ventas, etc.) y debemos encontrar cual es el módulo que abrió una transacción pero nunca la cerró porque las transacciones que se abren y nunca se cierran solamente pueden causar problemas y nunca nos otorgarán algún beneficio. También podemos saber si un usuario se conectó hoy, a que hora se conectó, que operaciones realizó, etc.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

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

Verificando que SET TRANSACTION no inicia una transacción

1 comentario

En algunos documentos había leído que SET TRANSACTION iniciaba una transacción y en otros que no la iniciaba. Yo tenía entendido que no la iniciaba, pero me quedó la duda, así que decidí comprobar quien tenía razón. ¿SET TRANSACTION inicia una transacción o no la inicia?

Después de conectarme a la Base de Datos con ISQL escribí un SELECT que me muestra datos de todas las transacciones activas, como puedes ver en la Captura 1.

TRANSACCIONES2

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

El SELECT me muestra que hay dos transacciones activas, lo cual es lo correcto. Una de ellas es interna del ISQL y la otra es donde los usuarios escriben sus comandos.

TRANSACCIONES3

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

Escribí un ROLLBACK para finalizar la transacción actual del usuario.

TRANSACCIONES4

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

Después escribí un SET TRANSACTION que me servirá para poder verificar a que hora se inició la transacción.

TRANSACCIONES5

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

Y a continuación escribí otro SELECT, para ver los datos de las transacciones activas. Como muestra la Captura 4 hay dos transacciones activas: la interna del ISQL y la del usuario. La del usuario corresponde al momento en que se hizo el SELECT o sea que la transacción se inició con el SELECT, no con el SET TRANSACTION. Si se hubiera iniciado con el SET TRANSACTION entonces ambas transacciones hubieran tenido 23:38 en la columna MON$TIMESTAMP, pero no es así. La transacción interna del ISQL sí inició a las 23:38 pero la transacción del usuario inició a las 23:42 que es el momento en que se escribió el SELECT.

En otras palabras, está comprobado que el SET TRANSACTION no inicia la transacción sino que sirve para establecer los parámetros que serán utilizados por la siguiente transacción. La transacción la inicia el Cliente del Firebird cuando no hay una transacción activa y se ejecuta un comando (INSERT, UPDATE, DELETE, SELECT, EXECUTE PROCEDURE, etc.)

Artículos relacionados:

Entendiendo a 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

Older Entries