Como habíamos visto en este artículo:

https://firebird21.wordpress.com/2013/06/14/la-arquitectura-mga/

cuando se actualiza (UPDATE) o se borra (DELETE) un registro el Firebird guarda en la Base de Datos la versión anterior de ese registro. ¿Para qué hace eso? Para poder revertir al registro original cuando se hace un ROLLBACK.

Un ROLLBACK se hace si ocurrió un error o si el usuario cambió de idea y no quiere guardar lo último que hizo, o si se cerró anormalmente la conexión.

Por lo tanto, cada comando UPDATE y cada comando DELETE le agrega un registro a la tabla respectiva (en el caso del DELETE el nuevo registro solamente tiene un marca que le indica al Firebird que ese registro está «borrado»).

Veamos un ejemplo de UPDATE:

El precio de «Televisor Toshiba de 20 pulgadas» es de 120 dólares. Como se está vendiendo poco ya que la mayoría de la gente ahora prefiere televisores de más pulgadas se decidió disminuir su precio a 100 dólares, tratando de conseguir que aumenten las ventas al disminuir el precio.

Entonces, en nuestra tabla de PRODUCTOS, luego del correspondiente UPDATE, tendríamos:

SWEEP1

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

Ahora hay dos posibilidades:

  1. Que la transacción termine con un COMMIT exitoso
  2. Que la transacción termine con un ROLLBACK

Si la transacción terminó con un COMMIT exitoso entonces el registro antiguo, el que tiene el TID 143 ya no sirve, es inútil. Pero el Firebird no lo elimina de la Base de Datos, lo deja ahí. Y eso implica que está ocupando espacio inútilmente.

Si la transacción terminó con un ROLLBACK entonces el registro nuevo, el que tiene el TID 279 ya no sirve, es inútil. Pero el Firebird no lo elimina de la Base de Datos, lo deja ahí. Y eso implica que está ocupando espacio inútilmente.

De lo anterior se deduce que cada vez que escribes el comando UPDATE dejas un registro inservible dentro de la Base de Datos. O el original queda inservible o el actualizado queda inservible.

Hay por lo tanto dos tipos de registros inservibles:

  • Los dejados por los COMMIT
  • Los dejados por los ROLLBACK

¿Hay diferencia si el registro inservible fue dejado por un COMMIT o por un ROLLBACK?

Sí, la diferencia es que los registros inservibles dejados por los COMMIT pueden ser eliminados automáticamente durante la recolección de la basura (ver más abajo), en cambio los dejados inservibles por los ROLLBACK nunca son eliminados automáticamente.

¿Qué es la «basura»?

Esos registros inservibles, inútiles, que fueron dejados por los UPDATE o por los DELETE siguen ocupando espacio dentro de la Base de Datos, pero como ya son inservibles y totalmente inútiles se les llama «basura».

¿Cuál es el problema con la basura?

Que ocupa espacio inútilmente dentro de la Base de Datos y por lo tanto ésta es más grande de lo que debería ser y además se vuelve cada vez más lenta.

¿Qué significa «garbage collection»?

En castellano: recolección de la basura. Cuando se recolecta la basura todos esos registros inservibles dejados por los COMMIT son eliminados permanentemente y definitivamente de la Base de Datos. Como consecuencia de ello, la Base de Datos queda con espacio reutilizable y además las operaciones dentro de ella (INSERT, UPDATE, DELETE, FETCH, SELECT) se realizan más rápidamente.

¿Cuándo se realiza la «garbage collection»?

Cada vez que un registro es «tocado» por un SELECT toda la basura relacionada con ese registro como consecuencia de los COMMIT es eliminada. En otras palabras, si al escribir un SELECT un registro está en el resultado obtenido entonces toda la basura relacionada con ese registro, producida por los  COMMIT, es eliminada.

Fíjate que solamente el SELECT elimina a la basura, los demás comandos: INSERT, UPDATE, DELETE, no la eliminan, la dejan así mismo como estaba.

¿Cuál es la forma más rápida de eliminar toda la basura de una tabla?

Escribir el comando:

SELECT
   COUNT(*)
FROM
   MiTabla

Lo que hace ese comando es contar la cantidad de registros que tiene la tabla pero para hacerlo debe recorrer la tabla desde el primer registro hasta el último registro porque el Firebird no guarda en alguna parte la cantidad de registros de la tabla. Por lo tanto, todos los registros de esa tabla están involucrados en el SELECT y por consiguiente en todos esos registros es recolectada la basura. Si la tabla tiene 12.000 registros entonces SELECT COUNT(*) recorre los 12.000 registros y el «garbage collection» elimina toda la basura que haya encontrado en cualquiera de esos 12.000 registros.

Recuerda que esta forma de eliminar a la basura solamente elimina a la basura que dejaron los COMMIT, la basura dejada por los ROLLBACK no se puede eliminar así.

¿Cuál es el problema con recolectar la basura usando SELECT?

Que para recolectar la basura de todas las tablas debes hacer SELECT COUNT(*) en todas las tablas o esperar que algún SELECT involucre a los registros que tienen basura. A veces, puede ocurrir que se hizo el UPDATE de un registro pero nunca se hizo un SELECT que involucre a ese registro y por lo tanto la basura que dejó el UPDATE permanece dentro de la Base de Datos.

Además, no te olvides que cuando se ejecuta un SELECT solamente se recolecta la basura que dejaron los COMMIT, la basura dejada por los ROLLBACK continúa allí.

¿Qué es el sweep?

El sweep (en castellano: barrido, de barrer con una escoba) es un proceso que recorre toda la Base de Datos y elimina toda la basura que se encuentra en ella, tanto la proveniente de los COMMIT como la proveniente de los ROLLBACK. Cuando el sweep finaliza la Base de Datos está bien limpia, sin basura.

¿Cuándo se realiza el sweep?

El sweep se puede realizar automáticamente o manualmente. Automáticamente es cuando lo inicia el propio Firebird y manualmente es cuando lo inicia un programa (por ejemplo: GFIX y GBAK pueden iniciar el sweep).

Sweep automático

Cada Base de Datos tiene una entrada denominada «sweep interval» o sea intervalo del sweep. Es un número de tipo INTEGER  y por lo tanto su valor puede estar entre 0 y 2.147.483.647. Por defecto su valor es 20.000.

Cuando la diferencia entre la OST y la OAT es mayor que el intervalo del sweep, se inicia el sweep. Por ejemplo:

OST = 45.201

OAT = 25.200

Sweep interval = 20.000

Diferencia = OST – OAT = 45.201 – 25.200 = 20.001

Como la diferencia es mayor que el intervalo del sweep, se inicia el sweep automático.

Si no se quiere realizar un sweep automático entonces el intervalo del sweep debe ser 0 (cero)

¿Cuál es el problema con el sweep?

Que este proceso de recorrer toda la Base de Datos y de eliminar toda la basura que hay en ella es lento, en algunos casos extremadamente lento y los usuarios se quejan de que todas las operaciones (INSERT, UPDATE, DELETE, FETCH, SELECT) se realizan muy despaciosamente. Y por supuesto podría ocurrir que el sweep automático se inicie cuando los usuarios están más apurados, más impacientes y por culpa del sweep todas sus transacciones son más lentas que una tortuga con tres patas. Es por lo tanto normal que el DBA (Administrador de la Base de Datos) ponga el intervalo del sweep en 0 (cero) y de esa manera realizará el sweep manualmente, en momentos en que nadie está usando la Base de Datos (o cuando muy pocos usuarios la están usando).

Pero …. a veces el DBA se olvida de que dejó el intervalo del sweep en cero y la Base de Datos se va volviendo cada vez más grande y más lenta por toda la basura que tiene acumulada.

En otras palabras, se necesita un DBA con cerebro, algo que no siempre se consigue.

Aprovechar el backup para hacer el sweep

Cuando haces un backup usando el programa GBAK tienes la opción de que también se haga el sweep de la Base de Datos. Esa es la opción por defecto y la recomendable. Así, cuando finaliza el programa GBAK puedes estar seguro de que el archivo de backup generado no tiene basura. Recuerda: la Base de Datos original continúa con toda la basura que tenía, el backup generado es el que no tiene basura.

Usando el programa GFIX para hacer el sweep

Una de las opciones de este programa nos permite pedirle que haga el sweep:

GFIX -sweep -user SYSDBA -password masterkey MiBaseDatos

Un pequeño «defecto» que tiene el programa GFIX es que no te avisa que finalizó exitosamente y eso confunde a los principiantes. O sea, si termina sin ningún mensaje significa que todo estuvo ok, si ocurrió algún problema entonces termina con un mensaje de error.

Conclusión:

El uso normal de la Base de Datos va dejando basura dentro de ella. Esa basura debe ser eliminada en algún momento porque de no eliminarse solamente causará que la Base de Datos tenga un tamaño mayor que el necesario y además que todas las transacciones sean más lentas de lo que deberían. La eliminación de la basura puede hacerse en forma automática (cuando el intervalo del sweep es mayor que cero y la diferencia entre la OST y la OAT es mayor que ese intervalo) o en forma manual (cuando el intervalo del sweep es cero y en ese caso hay que ejecutar el programa GFIX). También se elimina la basura cuando se hace un backup usando el programa GBAK y no se especifica la opción -garbage collection.

Artículos relacionados:

La arquitectura MGA

Entendiendo a las transacciones

Entendiendo a los identificadores de las transacciones

El índice del blog Firebird21