Eligiendo el tamaño adecuado de las páginas de la Base de Datos

Deja un comentario

En este artículo ya hemos visto lo que son las páginas de la Base de Datos:

Entendiendo las páginas de la Base de Datos

y sabemos que esas páginas pueden tener 3 tamaños posibles:

  • 4096 bytes
  • 8192 bytes
  • 16384 bytes

¿hay alguna diferencia en el rendimiento si la Base de Datos tiene alguno de esos tamaños de página?

Sí, si tiene el tamaño adecuado entonces todas las operaciones serán más rápidas (a veces, bastante más rápidas) que si tiene un tamaño inadecuado. Las operaciones que realiza el Firebird (INSERT, UPDATE, DELETE, SELECT, FETCH) siempre afectan a una o más páginas de la Base de Datos, por lo tanto utilizar el tamaño de página adecuado es importante

entonces la pregunta ahora es ¿cuál de esos tres tamaños es el más adecuado para mi Base de Datos?

 Pues bien, la respuesta más simple es “prueba y error”. O sea, pruebas con un tamaño, luego pruebas con otro, y luego pruebas con el tercero. Comparas los desempeños y eliges el que te pareció mejor.

Desde luego que “prueba y error” es una posibilidad. Como hay solamente 3 tamaños distintos entonces es factible de realizar. Sin embargo, podemos mejorar un poco nuestro análisis para determinar el tamaño más conveniente.

  1. Tamaño de la Base de Datos. Si alguna tabla tiene o tendrá más de 100.000.000 de filas entonces elige un tamaño de página de 16384 bytes porque en tablas tan grandes los índices también serán gigantescos y por lo tanto tendrán mucha profundidad (el Firebird usa índices B-Tree, y en tales índices una profundidad mayor que 3 empieza a ser problemática).
  2. El tamaño del caché que usa la Base de Datos. Las bases de datos de Firebird tienen una memoria caché, es decir usan una porción de la memoria RAM para realizar sus procesos. Un error frecuente de los principiantes es pensar “cuanto más grande el caché, mejor”. Bien, eso no es tan así. Si fuera tan sencillo entonces el Firebird por su propia cuenta se asignaría el caché más grande posible. En un Sistema Operativo de 32 bits la mayor cantidad de memoria que puede ser direccionada es de 4 Gb (o sea, 2 elevado a la 32), pero el Windows limita esa cantidad, para que un solo proceso no esté usando toda la memoria. Por defecto, un proceso puede usar como máximo 2 Gb aunque en el archivo CONFIG.INI puede cambiarse hasta 3 Gb. Si usamos SuperServer y en el archivo FIREBIRD.CONF ponemos en la entrada DefaultDbCachePages el número 100000 y el tamaño de nuestras páginas es de 16384 bytes entonces el caché de cada Base de Datos consumirá 1.6 Gb. Lo cual implica que podremos tener abierta una sola Base de Datos, porque 1.6 Gb por 2 es 3.2 Gb, que sobrepasa el máximo de 3 Gb que el Sistema Operativo nos permite direccionar. Pero lo peor es que un caché tan gigantesco tampoco nos asegura que nuestras operaciones serán rapidísimas ¿por qué? porque el propio Sistema Operativo usa su propio caché en operaciones repetitivas de lectura en disco y por lo tanto no se usará el caché del Firebird, ocupará mucha memoria pero no se lo usará ¿Y entonces? bueno, en general un tamaño de página de 16384 bytes y un tamaño de caché moderado (o sea, alrededor de 20000) es lo más adecuado.
  3. Cantidad de filas por página. A mayor tamaño de la página, mayor cantidad de filas se pueden guardar en ella y por lo tanto la Base de Datos necesita de menos páginas. Lo normal es que si una Base de Datos tiene pocas páginas sea menos propensa a corromperse que si tiene muchas páginas. En consecuencia, un tamaño de página de 16384 bytes es preferible porque será más difícil que la Base de Datos se corrompa.
  4. Tamaño del clúster. Cuando se formatea un disco duro se debe elegir el tamaño del clúster, el cual en NTFS es de 512 bytes por defecto pero puede ser cambiado.

Si el tamaño de la página es mayor que el del clúster entonces cuando se quiere leer una página se debe leer más de un clúster desde el disco duro y eso es lento. Por ejemplo:

Tamaño de la página = 4096 bytes

Tamaño del clúster = 512 bytes

implica que leer una sola página de la Base de Datos requiere leer 8 clústers en el disco duro (ya que 512 * 8 = 4096). Lo mismo cuando se quiere escribir en una página, se requerirá escribir en 8 clústers. Y si los clústers no están contiguos eso hará aún más lenta a la operación (nosotros no podemos saber si estarán contínuos o no, porque eso es de incumbencia del Sistema Operativo).

 Si el tamaño de la página es menor que el tamaño del clúster a veces puede ser beneficioso cuando se lee, sin embargo cuando se escribe se tardará más. Por ejemplo:

Tamaño de la página = 4096 bytes

Tamaño del clúster = 8192 bytes

Como el Sistema Operativo no puede leer menos que un clúster, un clúster es lo mínimo que puede leer desde el disco duro, cada vez que lea un clúster estará trayendo 2 páginas. Eso puede ser bueno si necesitaremos luego los datos que están en la segunda página pero si no es así entonces se leyeron 4096 bytes inútiles ¿por qué? porque los primeros 4096 bytes sí los usamos, esos fueron los que pedimos, pero los siguientes 4096 nunca los usamos y por lo tanto fueron leídos inutilmente. A su vez, cuando necesitemos escribir lo haremos por duplicado porque cuando escribamos en la primera página escribiremos en el clúster y cuando escribamos la segunda página también escribiremos en el clúster.

¿Lo mejor?

Que el tamaño de la página y el tamaño del clúster sean iguales.

El tamaño adecuado puede cambiar con el tiempo

Un punto muy, pero muy importante a tener en cuenta es el siguiente: el mejor tamaño de página hoy puede no ser el mejor dentro de un mes o dentro de un año.

¿Por qué?

Porque las bases de datos son dinámicas, no son estáticas, constantemente se les están insertando, actualizando, y borrando filas. Un tamaño de página excelente cuando la Base de Datos tenía una tamaño de 50 Mb puede ser horrible cuando creció hasta tener un tamaño de 2 Gb.

Así que debemos recordar que a veces cambiar el tamaño de las páginas puede ser una muy buena alternativa para que todas las operaciones se realicen más rápidamente.

Conclusión:

Si nuestra Base de Datos tiene un tamaño de página adecuado entonces todas las operaciones que se realicen en ella (INSERT, UPDATE, DELETE, SELECT, FETCH) serán rápidas. Pero si no es así, entonces esas operaciones serán más lentas de lo que deberían.

Como hay solamente 3 tamaños de página posibles entonces es muy fácil realizar tests de “prueba y error”. Sin embargo, también podemos tener en cuenta algunos parámetros para hallar el tamaño de página más adecuado y arriba se detallan esos parámetros.

Algo importante a tener en cuenta es que el tamaño del clúster del disco duro debe ser igual al tamaño de la página de la Base de Datos, para conseguir el máximo rendimiento posible.

Artículos relacionados:

Entendiendo las páginas de la Base de Datos

El índice del blog Firebird21

El foro del blog Firebird21

Anuncios

Entendiendo las páginas de la Base de Datos

Deja un comentario

El Firebird guarda todos los datos en “páginas”. Nada hay dentro de una Base de Datos que no esté dentro de una página.

¿Qué es una página?

Es una cantidad predefinida y fija de bytes que son tratados como una unidad.

 ¿Cuál es el tamaño en bytes de una página?

Es el tamaño que se definió cuando se creó la Base de Datos. Si no se especificó un tamaño entonces tendrá el valor por defecto que en Firebird 2.5 es de 4096 bytes. Los tamaños posibles son los siguientes:

  • 4096 bytes
  • 8192 bytes
  • 16384 bytes

¿Se puede cambiar el tamaño en bytes de las páginas?

Sí, se puede, para eso se debe usar el programa GBAK. Al restaurar un backup se puede especificar el tamaño que tendrán las páginas de la Base de Datos restaurada. La opción para ello es -page_size [tamaño], por ejemplo: -page_size 8192

Recuerda que el tamaño de las páginas de la Base de Datos original no cambia, el que cambia es el tamaño de las páginas de la Base de Datos restaurada.

¿Y qué ocurre si especifico un tamaño que no sea ninguno de los anteriores?

Entonces el Firebird usará uno de los anteriores. Si el tamaño que especificaste es menor que 4096, usará 4096. Si es mayor que 4096, usará el tamaño predefinido que sea menor al que especificaste. Por ejemplo, si especificaste 16000, usará 8192 porque 8192 es menor que el tamaño que especificaste.

 ¿Y cómo puedo saber el tamaño de las páginas de mi Base de Datos?

Hay dos formas:

1. Usando el programa GSTAT con la opción -h, como vemos a continuación:

PAGES01

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

El número que verás a continuación de “Page size” siempre será uno de los siguientes: 4096, 8192, 16384

2. Haciendo un SELECT a la tabla MON$DATABASE

SELECT
   MON$PAGE_SIZE
FROM
   MON$DATABASE

NOTA: Versiones antiguas de Firebird también permitían 1024 y 2048, pero ahora esos tamaños ya son obsoletos.

¿Cuántas clases de páginas distintas hay?

Aunque todas las páginas tienen exactamente el mismo tamaño, se las utiliza para distintas cosas. Para saber en que se utiliza cada página tienen un número hexadecimal que las identifica al cual se le llama “tipo de página”.

  • 0x01. Es la Header Page (página de cabecera) y solamente hay una. En ella se guardan datos tales como: el tamaño de las páginas, la versión del ODS, la transacción más antigua, la última transacción activa, la siguiente transacción, etc.
  • 0x02. Es una Page Inventory Page (página de inventario). Puede haber varias. Su sigla es PIP. Siempre la primera PIP está a continuación de la Header Page. Se usa para saber cuales son las páginas que tiene actualmente la Base de Datos y si están libres para ser usadas (o sea, “disponibles”) o no.
  • 0x03. Es una Transaction Inventory Page (página de inventario de las transacciones). Siempre hay al menos una. Aquí se guardan el número de las transacciones y su estado (activa, limbo, confirmada, desechada). El mayor número posible de transacción es 2.147.483.647, cuando una Base de Datos alcanzó a ese número de transacciones se debe hacer un ciclo backup/restore para que el número de la transacción regrese a 1.
  • 0x04. Es una Pointer Page (página de punteros). Hay al menos una por cada tabla (de metadatos o del usuario) que tiene la Base de Datos. En la Pointer Page se guardan los números todas las páginas de datos que pertenecen a una sola tabla. Eso significa que en una página de datos solamente puede haber filas de una sola tabla, nunca se mezclan filas de una tabla con las de otra tabla en una página de datos. Las tablas grandes tienen muchas Pointer Page.
  • 0x05. Es una Data Page (página de datos). Hay al menos una por cada tabla que tiene filas (tanto sean metadatos como del usuario). Todos los datos de esta página corresponden a una sola tabla.
  • 0x06. Es una Index Root Page (página del índice raíz). Cada tabla de la Base de Datos tiene una Index Root Page, la cual describe los índices que tiene esa tabla. Aunque una tabla no tenga índices igual tiene una Index Root Page.
  • 0x07. Es una Index B-Tree Page (página de índice B-Tree). Si una tabla no tiene índices, no tendrá una página de tipo 0x07. Todos los datos de una página Index B-Tree corresponden a un solo índice de una sola tabla.
  • 0x08. Es una BLOB Data Page (página de datos para columnas de tipo BLOB). Solamente existen para tablas que tienen al menos una columna de tipo BLOB. En esta página se guarda el contenido de esas columnas. Todos los datos corresponden a una sola columna de una sola tabla.
  • 0x09. Es una Generator Page (página de generadores). Hay al menos una por cada Base de Datos, aunque ningún generador (también llamado “secuencia”) haya sido definido.
  • 0x0A. Es una Write Ahead Log Page (página de escribir por delante el log). Hay al menos una por cada Base de Datos, pero actualmente no se la está usando, es un desperdicio de espacio, y probablemente ya no exista en Firebird 3.0

¿Qué sucede con una página de datos cuando las filas que guardaba son eliminadas?

Supongamos que en una página se encuentran las filas de la tabla VENTAS y escribes DELETE FROM VENTAS borrando así a todas esas filas. ¿Qué pasa con la página, se la elimina de la Base de Datos? No, permanece ahí, pero en la PIP (Page Inventory Page) se la marca como “disponible”. O sea que puede ser usada nuevamente, y cuando el Firebird necesite una nueva página usará a una de las “disponibles”. ¿Por qué eso? Porque para el Firebird es mucho más rápido usar una página “disponible” (es decir, libre, que nadie la está usando) que alojar una nueva página en el disco duro.

De la misma manera, cuando se hace una “recolección de basura” pueden quedar muchas páginas “disponibles”. Eso es debido a que la “recolección de basura” no elimina a esas páginas de la Base de Datos, sino que las marca como “disponibles”.

Por supuesto que esto implica que si hay muchas páginas “disponibles” hay mucho espacio dentro de la Base de Datos que no está siendo usado para algo útil. Si quieres disminuir el tamaño de la Base de Datos puedes hacer un ciclo backup/restore para que todas esas páginas “disponibles” desaparezcan físicamente.

Resumiendo:

Todo dentro de una Base de Datos de Firebird se guarda dentro de una página, nada está afuera de una página. Todas las páginas tienen el mismo tamaño, aunque se las use para cosas distintas. Ese tamaño se puede especificar al crear la Base de Datos o puede ser cambiado cuando se restaura un backup con el programa GBAK. Se puede usar el programa GSTAT con la opción -h o un SELECT a la tabla MON$DATABASE para conocer el tamaño de las páginas. Cada página dentro de la Base de Datos tiene un número hexadecimal que la identifica y al cual se conoce como el “tipo de página”. Todos los datos dentro de una página corresponden a la misma cosa, nunca se mezclan. Por ejemplo, si una página se usa para guardar las filas de la tabla VENTAS en esa página solamente habrá filas de la tabla VENTAS, jamás habrá en esa página filas de la tabla EMPLEADOS. Cuando todo el contenido de una página de datos es eliminado a esa página se la marca como “disponible” y puede ser reutilizada; si se desea eliminar a todas las páginas “disponibles” hay que hacer un ciclo backup/restore.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Valores de las variables en un stored procedure

Deja un comentario

Leyendo un comentario que escribió Jaume en el artículo:

Entendiendo a los Stored Procedures

pensé que alguien más podría tener esa misma confusión y por tal motivo estoy escribiendo este artículo. Es para aclarar el comportamiento de las variables en un stored procedure.

Veamos un ejemplo de un stored procedure muy sencillo, sólo para mostrar donde puede existir confusión:

CREATE PROCEDURE VALOR_ANTERIOR
   RETURNS(
      tcNombre TYPE OF COLUMN CLIENTES.CLI_NOMBRE)
AS
BEGIN

   tcNombre = 'PRUEBA';

   FOR SELECT
      CLI_NOMBRE
   FROM
      CLIENTES
   WHERE
      CLI_IDENTI > 1000000
   INTO
      :tcNombre
   DO
      SUSPEND;

   IF (tcNombre = 'PRUEBA') THEN
      SUSPEND;

END;

Evidentemente este es un stored procedure seleccionable (sabemos eso porque tiene el comando SUSPEND dentro de él). Y la pregunta es: ¿qué valor o valores devolverá este stored procedure cuando lo ejecutemos con el comando SELECT?

SELECT
   *
FROM
   VALOR_ANTERIOR

Bien, eso depende de si hay alguna fila que tenga en la columna CLI_IDENTI un valor mayor que 1000000 ó no. Si hay una o más filas, entonces devolverá el nombre de los respectivos clientes pero si ninguna fila cumple con esa condición entonces devolverá la palabra ‘PRUEBA’.

¿Por qué devuelve ‘PRUEBA’ y no devuelve NULL?

Uno podría pensar que si ninguna fila cumple con la condición entonces debería devolver NULL, sin embargo no es así, devuelve el valor que anteriormente tenía la variable tcNombre, en este caso ‘PRUEBA’. ¿Por qué eso?

Eso es porque un SELECT puede devolver cero filas, eso ocurre cuando la tabla no tiene filas o cuando ninguna fila cumple con la condición. En ese caso el valor que tenían las variables asignadas por el SELECT (las que se encuentran después de la cláusula INTO) no puede cambiar ya que ninguna fila fue retornada. La asignación a esas variables se hace solamente después de obtener una fila, como es lógico.

En consecuencia, si ninguna fila es retornada todas esas variables mantienen el valor que tenían anteriormente, porque ninguna asignación fue hecha a ellas. En este caso tcNombre seguirá valiendo ‘PRUEBA’.

Para que tcNombre valiera NULL, el Firebird tendría que asignarle NULL antes de ejecutar al SELECT pero ¿para qué haría eso? sería una causa de conflicto porque una columna de un SELECT puede legítimamente valer NULL y en ese caso ¿cómo se diferenciaría entre un NULL previamente asignado y un NULL como valor legítimo de una columna? No habría forma de diferenciar a un NULL del otro, por lo tanto el Firebird hace lo más lógico, coherente, y racional: asignarle valores a las variables solamente después de obtener una fila del SELECT, nunca antes.

Así que, el Firebird hace lo correcto.

Por lo tanto, si un SELECT no retorna filas, todas las variables que se encuentren después de la claúsula INTO mantendrán el valor que tenían antes del SELECT.

No asumas que el valor de dichas variables será NULL, porque podría no ser así.

Artículos relacionados:

Entendiendo a los Stored Procedures

El índice del blog Firebird21

El foro del blog Firebird21

 

Creando un archivo batch para ejecutar a ISQL

2 comentarios

Desde los ya lejanos tiempos del MS-DOS disponemos de la posibilidad de crear archivos de texto que pueden procesar comandos, a esos archivos anteriormente se los llamaba “de lotes” y ahora el nombre más común es “de comandos”.

Los archivos de lotes tienen la extensión .BAT (de batch = lote, en inglés) y los archivos de comandos tienen la extensión .CMD (de command = comando, en inglés).

Aunque las extensiones son distintas funcionan exactamente igual.

¿Y para qué necesitaríamos crear un archivo de lotes o de comandos?

Bueno, en general no los necesitaremos pero a veces es interesante saber como utilizarlos porque nos pueden quitar de apuros. Por ejemplo, un usuario nos dice que necesita ver un informe que nuestra aplicación no le provee. Una solución simple y sencilla es crear un archivo de texto con extensión .BAT o .CMD que le enviamos por e-mail o algún otro medio electrónico, le pedimos que ejecute ese archivo y listo, asunto solucionado. Desde luego que algo así es un parche, algo momentáneo, para sacarnos del apuro, más tarde haremos las cosas bien, con una pantalla bien diseñada y todo eso, pero mientras tanto ese archivo nos soluciona el problema.

Un ejemplo de un archivo de lotes o de comandos

A continuación verás el código fuente de uno de tales archivos, debes abrir el Bloc de Notas, copiar el código y luego grabarlo con la extensión .BAT o .CMD, verifica que se grabe con una de esas dos extensiones y no con .TXT o alguna otra porque en ese caso no te funcionará.

@ECHO OFF

REM --- Asignando valores a las variables de entorno

SET CARPETAORIGINAL=%CD%
SET CARPETAISQL="C:\Program Files\Firebird\Firebird_2_5\bin\"
SET SCRIPT="E:\SQL\DATABASES\SCRIPT1.SQL"
SET BASEDATOS='E:\SQL\DATABASES\BLOG_DB.FDB'
SET USUARIO=SYSDBA
SET CONTRASENA=masterkey

REM --- Creando el archivo de script

ECHO SET NAMES ISO8859_1;>%SCRIPT%
ECHO SET SQL DIALECT 3;>>%SCRIPT%
ECHO -->>%SCRIPT%
ECHO CONNECT %BASEDATOS% USER %USUARIO% PASSWORD %CONTRASENA%;>>%SCRIPT%
ECHO -->>%SCRIPT%
ECHO SET AUTODDL ON;>>%SCRIPT%
ECHO -->>%SCRIPT%
ECHO SELECT CLI_IDENTI, CLI_NOMBRE FROM CLIENTES;>>%SCRIPT%
ECHO -->>%SCRIPT%
ECHO EXIT;>>%SCRIPT%

REM --- Ejecutando el programa ISQL.EXE con el archivo de script

CD /D %CARPETAISQL%
ISQL<%SCRIPT%

REM --- Regresando a la carpeta donde se encuentra el archivo batch

CD /D %CARPETAORIGINAL%

REM --- Finalizando el archivo batch

ECHO .
ECHO El script ha finalizado.
PAUSE

Entendiendo el archivo de lotes o de comandos anterior

Si aún no has usado archivos de lotes o de comandos (son sinónimos) entonces el código anterior podría parecerte algo muy complicado. Pues no, no es así, es sumamente sencillo de entender. Veamos:

  • @ECHO OFF se usa para que no se muestre la línea que se está ejecutando. Si escribes la palabra REM delante de esta línea (REM significa que es un comentario) verás la diferencia
  • Si escribes la palabra REM y un espacio en blanco, todo lo que escribas a continuación en esa misma línea será un comentario
  • El comando SET sirva para declarar una variable y asignarle un valor. IMPORTANTE: No debes dejar espacios en blanco ni antes ni después del símbolo de igual, o no te funcionará la variable que declaraste.
  • Si se rodea a una palabra con el símbolo de porcentaje %PALABRA%, eso significa que se trata de una variable, no de una constante. Y en ese caso se usará el valor que tenga la variable
  • El comando ECHO envía a la pantalla el texto que se encuentra a continuación
  • La salida se puede redirigir, eso es, enviar a otro lado. Por ejemplo, el comando ECHO por defecto envía la salida a la pantalla pero si lo deseamos podemos redirigirla a la impresora, a un archivo de texto, a un puerto serie, etc.
  • Para redirigir la salida se puede usar un símbolo mayor que > o dos símbolos mayor que >>. En el primer caso, se crea un archivo con el nombre que viene a continuación y se le agrega la línea. En el segundo caso se agrega esa línea al final del archivo cuyo nombre viene a continuación, o sea que el archivo ya debería existir
  • La entrada también se puede redirigir. Eso significa que le podemos enviar parámetros a un programa y esos parámetros pueden ser variables. Para redirigir la entrada se usa un símbolo menor que <
  • El comando PAUSE muestra el mensaje: Presione una tecla para continuar …

Explicando el archivo de lotes o de comandos anterior

Ahora que ya sabemos el significado de los distintos token, podemos entender como funciona el archivo de lotes o de comandos:

  1. Con @ECHO OFF se evita que cada línea que se ejecuta se muestre en la pantalla
  2. Con el comando SET se declaran variables y se les asignan valores. Si nos fijamos en la variable CARPETAORIGINAL veremos que su valor es %CD%. ¿Qué significa eso? que se guardará en ella la carpeta actual, la carpeta donde se encuentra el archivo de lotes, por ejemplo: E:\SQL\DATABASES\, ¿por qué eso? porque al usar %PALABRA% lo que se hace es obtener el valor de esa variable. Hay algunas variables pre-definidas, o sea que el Sistema Operativo se encarga de asignarles un valor, algunas de esas variables son %DATE%, %TIME%, %USERNAME%, %CD%, etc.
  3. Usamos el comando ECHO para crear un archivo de texto. Para que funcione, debemos redirigir la salida a ese archivo de texto. Recuerda que si a continuación de ECHO hay un solo símbolo > se crea el archivo pero en cambio si hay dos >> se agrega al final. La ruta y el nombre de ese archivo se encuentran en la variable %SCRIPT%
  4. Usaremos el archivo de texto que estamos creando para conectarnos a la Base de Datos y para ejecutar un comando SELECT en ella. Desde luego que tú podrías tener muchos SELECTs, INSERTs, UPDATEs, etc., lo que quieras
  5. A continuación de CONNECT vemos que dice %BASEDATOS%. Eso significa que tratará de conectarse a la Base de Datos cuya ruta y nombre se encuentra en la variable %BASEDATOS%
  6. Así mismo, se usará el contenido de las variables %USUARIO% y %CONTRASENA% para obtener el nombre del usuario y su contraseña, respectivamente
  7. Los ECHO – – solamente sirven para separar líneas, no tienen otra utilidad
  8. La línea CD /D %CARPETAISQL% sirve para ubicarse en el disco duro y en la carpeta cuyos datos se encuentran en la variable %CARPETAISQL%
  9. Estando en esa carpeta, se ejecuta el programa ISQL.EXE, el cual recibe como entrada el archivo de texto que creamos recién, y cuyo nombre se encuentra en la variable %SCRIPT%
  10. Cuando finaliza la ejecución del archivo (o sea, después del SELECT), finaliza el programa ISQL.EXE
  11. Se regresa a la carpeta original, o sea a la carpeta donde se encuentra el archivo .BAT o .CMD
  12. Se le muestra un mensaje al usuario, y se le pide que presione una tecla

Simplificando:

Este archivo .BAT o .CMD creó un archivo de texto con el nombre SCRIPT1.SQL en la carpeta E:\SQL\DATABASES\ para conectarse a la Base de Datos BLOG_DB.FDB que se encuentra en la carpeta E:\SQL\DATABASES\. Luego hizo un SELECT a la tabla de CLIENTES.

El resultado de todo lo anterior lo podemos ver a continuación:

BATCH2

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

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

En la Captura 1 vemos el archivo de texto creado, que en este caso tiene el nombre SCRIPT1.SQL (desde luego que tú puedes darle otro nombre si quieres) y en la Captura 2 vemos el resultado de ejecutar al programa ISQL.EXE cuando recibe como parámetro de entrada al archivo SCRIPT1.SQL

Conclusión:

Poder crear un archivo .BAT o .CMD para desde él ejecutar comandos del Firebird puede sernos de mucha utilidad en algunas ocasiones, es un arma más, una herramienta más, que tenemos y que debemos saber aprovecharla.

Desde luego que la técnica que hemos visto aquí no solamente sirve para el Firebird y para el programa ISQL.EXE, sirve para cualquier otro programa también, por ejemplo: GBAK.EXE, NBACKUP.EXE, GFIX.EXE, GSEC.EXE y para casi cualquier otro programa Windows.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Encontrando filas duplicadas

2 comentarios

En una Base de Datos bien diseñada nunca deberían existir filas duplicadas (o triplicadas, o cuadruplicadas, o…) pero a veces algo así sucede y debemos en primer lugar encontrar el motivo o la causa que las permitió y en segundo lugar eliminarlas.

¿Por qué hay que eliminarlas?

Porque si están duplicadas están sobrando, están de más, están aunque no deberían estar, y el tenerlas dentro de la Base de Datos solamente nos puede causar problemas y ningún beneficio: los informes tendrán más filas de las que deberían tener, los totales serán mayores a los reales, etc.

 ¿Y por qué causa tenemos filas duplicadas?

Si nuestra Base de Datos está bien diseñada sería imposible que tal cosa ocurra si los usuarios introducen los datos manualmente pero a veces los datos provienen de fuentes externas como un archivo de texto, una planilla Excel, una tabla .DBF, etc.

Y si está mal diseñada permitirá filas duplicadas. Un caso insidioso puede ocurrir cuando tenemos dos o más formularios que se utilizan para introducir datos en las tablas. Por ejemplo, una aplicación de Contabilidad tiene un módulo de Clientes y otra aplicación de Facturación también tiene un módulo de Clientes. Los usuarios pueden introducir datos de los clientes tanto desde la Contabilidad como desde la Facturación, algo así puede ser problemático de solucionar, con mayor razón cuando los programadores de ambas aplicaciones son distintas personas.

Y es en esos casos, en los cuales no tuvimos control cuando se insertaron las filas (porque provienen de un archivo de texto, una planilla Excel, una tabla .DBF, etc), o nuestro control fue mediocre, en que debemos verificar cuidadosamente que no existan filas duplicadas.

 Problemas que causan las filas duplicadas

  1. Los cálculos son incorrectos porque algunas filas son contadas más de una vez y deberían contarse una sola vez. Por lo tanto los informes serán incorrectos.
  2. Pueden existir datos incompletos en una fila, porque están en otra fila
  3. La velocidad de las operaciones en la Base de Datos (insertar, modificar, borrar, consultar) disminuye porque cuanto más grande es una Base de Datos más lentas son esas operaciones. Si hay filas duplicadas el tamaño de la Base de Datos será mayor que el necesario y por lo tanto las operaciones serán más lentas de lo que deberían ser
  4. Eliminar las filas duplicadas toma tiempo, no es algo instantáneo, y el personal desperdicia ese tiempo en encontrar y eliminar las filas duplicadas en lugar de dedicarlo a algo más importante

¿Cómo encontrar filas duplicadas?

Para estos casos lo mejor es crear un stored procedure seleccionable que se dedique a esa tarea, dicho stored procedure es muy sencillo, simplemente tendrá un FOR SELECT por cada tabla que nos interesa, algo como:

CREATE PROCEDURE SP_ENCONTRANDO_DUPLICADOS
   RETURNS(
      ftcNombre VARCHAR(255))
AS
   DECLARE VARIABLE lnCantidad INTEGER;
BEGIN

   FOR SELECT
      DEP_NOMBRE,
      COUNT(*)
   FROM
      DEPARTAMENTOS
   GROUP BY
      DEP_NOMBRE
   HAVING
      COUNT(*) > 1
   INTO
      :ftcNombre,
      :lnCantidad
   DO BEGIN
      SUSPEND;
   END

END;

Aquí hay una sola tabla, llamada DEPARTAMENTOS, y lo que se verifica es si el nombre de algún departamento está duplicado. Si ese es el caso entonces la condición COUNT(*) > 1 será verdadera y el nombre del Departamento será mostrado.

Un stored procedure más completo tendría varios FOR SELECT, uno por cada tabla que nos interesa verificar.

Lo importante a recordar es que no debemos permitir jamás, por ningún motivo, y bajo ninguna circunstancia, que en nuestras tablas existan filas duplicadas, porque si existen eso solamente podrá acarrearnos problemas.

Artículos relacionados:

Averiguando si hay datos duplicados

El índice del blog Firebird21

El foro del blog Firebird21

Newer Entries