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:
Captura 1. Si haces clic en la imagen la verás más grande
Ahora hay dos posibilidades:
- Que la transacción termine con un COMMIT exitoso
- 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:
Entendiendo a las transacciones
El índice del blog Firebird21 | Firebird SQL
Sep 11, 2013 @ 02:26:14
Romeo
Jun 02, 2015 @ 17:46:04
Hola! Buen dia… mucho gusto don Walter. Una pregunta, basado en la experiencia de usted… cual es el tiempo promedio que puede tardar en terminar (sabiendo que no hay un mensaje para tal fin) un barrido o sweeping a una base de datos? Lei que a un tipo le tardo 5 horas! :O :O :O
Saludos.
wrov
Jun 02, 2015 @ 21:06:31
Eso depende de dos factores:
1. Del tamaño de la Base de Datos
2. De la cantidad de basura que tiene la Base de Datos
En Firebird cada vez que una fila de cualquier tabla es modificada o borrada se genera basura, sí o sí. Por lo tanto es una cuestión fundamental de diseño tratar de que las modificaciones (comando UPDATE) y los borrados (comando DELETE) sean los mínimos posibles, porque cada UPDATE y cada DELETE genera basura, sin importar si la transacción terminó con un COMMIT o con un ROLLBACK, ya que en ambos casos se genera basura.
El usuario que tuvo la mala suerte de desencadenar el sweep verá que todas las operaciones que quiere realizar en la Base de Datos (INSERT, UPDATE, DELETE, SELECT) son más lentas que una tortuga de tres patas. Los demás usuarios no se verán afectados, pero él sí.
Es por eso que se recomienda hacer el sweep cuando nadie está conectado a la Base de Datos (y si eso no es posible, por lo menos cuando muy pocos usuarios estén conectados).
También se recomienda hacer el sweep periódicamente, no dejar pasar mucho tiempo entre un sweep y el siguiente porque alguna vez habrá que hacerlo y si ya hay mucha basura acumulada entonces el sweep se demorará demasiado tiempo en finalizar.
Resumiendo, pues sí, un sweep puede tardar 5 horas e inclusive más, pero eso solamente puede ocurrir en bases de datos que están mal diseñadas o mal administradas.
En una Base de Datos bien diseñada muy pocas veces se necesita hacer un UPDATE o un DELETE.
En una Base de Datos bien administrada los sweeps se realizan frecuentemente y en horarios donde nadie está usando la Base de Datos (o muy poca gente la está usando).
Saludos.
Walter.
Federico Mancinelli
Jun 08, 2016 @ 09:04:41
Buen día, respecto a la pregunta/respuesta:
«¿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.»
Quiere decir que además del «sweep interval» (automático) sería necesario ejecutar sweep con gfix para que este elimine los dejados por ROLLBACK?
Gracias
wrov
Jun 08, 2016 @ 17:36:39
No, cuando se realiza un sweep (manual o automático) toda la basura es eliminada, tanto la basura dejada por los COMMIT como la basura dejada por los ROLLBACK.
El sweep puede realizarse automáticamente (cuando la diferencia entre la OST y la OIT es mayor que el intervalo del sweep) o cuando se hace un backup con el programa GBAK, y también manualmente (con el programa GFIX).
Saludos.
Walter.
Andy Nin
Sep 21, 2016 @ 08:57:10
Saludos… Donde encuentro las variables OST y OIT para modificarla, y como me doy cuenta que en realidad se realizó el Sweep?
wrov
Sep 22, 2016 @ 23:17:14
Tú no las puedes modificar, son de uso interno del Firebird. Para verlas, puedes abrir una ventanita «Símbolo del sistema» en Windows y escribes: GSTAT -h MiBaseDatos
Si hay muchos usuarios conectados a la Base de Datos, no puedes saber si se realizó el sweep hace poco tiempo porque esos usuarios están constantemente abriendo y cerrando transacciones.
Si nadie está conectado a la Base de Datos, puedes detener al Servidor del Firebird y volver a iniciarlo. Si luego el comando GSTAT -h te muestra que la diferencia entre OST y OAT es mayor que 20000, entonces es aconsejable que ejecutes un sweep manual.
Saludos.
Walter.
Luis E Quiroz
Abr 11, 2018 @ 18:55:13
Saludos y gracias por su documento.
Donde se modifica el valor de SWEEP, si no quiero su ejecución, comenta debe de ser valor = 0
Gracias
wrov
Abr 11, 2018 @ 20:37:46
El programa GFIX.EXE es el que te permite determinar cual será el intervalo del sweep. Un valor de 0 (cero) significa que nunca será realizado automáticamente (aunque desde luego podrás realizarlo manualmente cuando quieras). El valor que establezcas para esa Base de Datos será el que se utilizará a partir de ese momento y hasta que lo vuelvas a cambiar.
Por ejemplo:
En la línea superior hemos establecido que el intervalo del sweep será de 500 para la Base de Datos CONTA.FDB (y solamente para esa Base de Datos, las otras bases de datos no se verán afectadas)
Si quieres saber cual es el intervalo del sweep que actualmente tiene una Base de Datos puedes usar el programa GSTAT.EXE
Al final de los datos mostrados verás las palabras «Sweep interval«. El número que está a continuación será 20000 (que es el valor por defecto para todas las bases de datos) o el número que hayas establecido con el programa GFIX.EXE y la opción -h
Recuerda que si el valor del «Sweep interval» es cero, será tu responsabilidad limpiar la Base de Datos de su basura, de vez en cuando. En este caso, el Firebird no realizará la tarea por tí.
Saludos.
Walter.