Cargando

Por Alfonso Ricaño El uso de un servidor SQL como Firebird/InterBase requiere del dominio de algunos conceptos que deben quedar claros para crear desarrollos cliente/servidor de calidad.

Como mencioné anteriormente, el utilizar Firebird/InterBase tiene muchas ventajas sobre los sistemas de datos basados en archivos, aunque para utilizarlo eficientemente debemos comprender algunos conceptos básicos y conocer la manera en que trabaja. En este artículo destaco las diferencias que hay entre los archivos de datos (dbf, db, mdb) y un servidor SQL como lo es Firebird/InterBase, así como las ventajas que tiene el usar esta tecnología y los conceptos necesarios para aprovecharla eficientemente.

Conceptos básicos

Para empezar, hay que entender que un servidor de base de datos -como Firebird/InterBase- es un proceso -es decir, un programa- ejecutándose en la computadora que se utiliza como servidor. Este proceso servirá de "intermediario" entre el programa cliente -que puede estar hecho con Delphi o C++Builder- y la base de datos física -en este caso, el archivo de base de datos, generalmente con extensión gdb-. Este programa -Firebird/InterBase-, debe atender todas las órdenes que le hacen los programas cliente. Estas órdenes tienen que ver con alguna base de datos, por ejemplo: insertar un registro, modificar el valor de una columna de una tabla, modificar la estructura de una tabla, eliminar un registro, obtener un conjunto de registros, etcétera. En el caso de los servidores de base de datos SQL, las órdenes deben ser escritas en ese lenguaje (SQL), pues es el único que el servidor entiende. Por ejemplo, para insertar un registro se debe escribir una orden INSERT, para eliminar uno o más registros se le debe dar una orden DELETE, etc. Como muchos de nosotros empezamos utilizando el formato Paradox o dBase cuando desarrollamos programas con Delphi/C++ Builder, mencionaré a continuación cuales son las diferencias principales entre utilizar estos formatos y utilizar Firebird/InterBase.

Diferencias entre formatos de archivos y servidores SQL

Cuando utilizamos un formato de archivos (Paradox, dBase, Access), el programa cliente (hecho con Delphi/C++ Builder) utiliza una interfaz prefabricada de acceso a los archivos, como la BDE. Menciono el término prefabricada porque son bibliotecas de funciones precompiladas (DLL) las cuales al ser utilizadas por el programa cliente, permiten abrir, modificar y obtener datos de los archivos de datos (los archivos DB, DBF, MDB). Cuando utilizamos programas cliente que acceden a una base de datos localizada en un servidor de archivos, lo que estamos haciendo es que todos los programas cliente abren físicamente el archivo de datos, mediante un proceso que se ejecuta en cada computadora cliente. Esta situación conlleva algunas desventajas como las siguientes: - Si alguna conexión de red o programa cliente tiene un problema, puede dañar el archivo de datos, ya que lo está abriendo directamente. - Las consultas a datos pueden llegar a ser muy lentas, ya que para seleccionar los registros de una consulta, cada programa cliente debe de pedir todo el archivo al servidor de archivos y toda esta información debe viajar por la red. - No se están aprovechando los recursos del servidor, solamente aquellos que optimizan el acceso a los archivos, dado que la máquina que ejecuta la consulta es la máquina cliente, además de que se crean cuellos de botella en la red, como se explica en el punto anterior. Ahora veamos las ventajas de utilizar un servidor SQL: * - Se minimizan los daños a la base de datos cuando falla uno de los programas clientes, pues lo peor que puede pasar es que se quede abierta una o más transacciones, las cuales posteriormente se pueden recuperar o eliminar. * - Se aprovecha al máximo las capacidades del hardware del servidor, debido a que el proceso de consulta de datos es ejecutado por el servidor SQL, el cual corre sobre el servidor de hardware. * - Se optimiza el tráfico en la red, debido a que cuando el servidor SQL devuelve los datos de una consulta al programa cliente, solamente envía el conjunto de datos producto de la consulta, y no el total de los datos de la tabla, como sucede cuando se utiliza un servidor de archivos. * Estas son únicamente las ventajas a nivel de acceso y transmisión de datos, ya que a nivel de seguridad e integridad tiene muchas más ventajas.

Otros conceptos necesarios

Una vez comprendido cómo funciona el esquema de un servidor de base de datos SQL, ahora expondré otros conceptos que se deben tener en cuenta cuando se empieza a trabajar con Firebird/InterBase.

Integridad referencial

La integridad referencial ya es tomada en cuenta por algunos formatos de base de datos de archivos, como Paradox. Esta característica permite asegurar que las relaciones entre las tablas de la base de datos siempre se cumplan, obteniendo consistencia en los datos y asegurando la integridad lógica de los mismos.

Triggers, o disparadores

Los triggers son algo así como procedimientos que se invocan automáticamente cuando se ejecuta una actualización, eliminación o inserción de un registro en alguna tabla de la base de datos, lo que permite poner algunas reglas de negocio de los sistemas al nivel de la base de datos. Esto tiene muchas ventajas, pues hay veces que en el desarrollo de un sistema con Delphi/C++ Builder, por ejemplo, se colocan este tipo de reglas en el código del programa. El problema es que si creamos otro módulo o programa que acceda la misma base de datos, deberemos copiar también estas reglas al nuevo programa para asegurar consistencia en los datos. El problema se agrava cuando se accede a la base de datos desde algún programa que no tenga implementadas tales reglas, como puede ser el Database Desktop.

Procedimientos almacenados

Los procedimientos almacenados son precisamente eso, procedimientos que se pueden ejecutar independientemente y que pueden o no devolver un resultado. Son muy útiles cuando se desea hacer un proceso complejo que involucre varias tablas y deba tener ciclos (bucles) y condicionales. En el caso de los procedimientos que devuelven resultados, este resultado se devuelve en forma de columnas (campos) de tal manera que estos procedimientos se pueden invocar mediante una orden de SQL de tipo SELECT. Los procedimientos que devuelven resultados pueden ser utilizados como tablas "virtuales" y son muy útiles sobre todo para crear reportes (informes).

Generadores

Un generador permite ir obteniendo números e ir incrementando o decrementando su valor. Son muy útiles para crear valores de campos únicos (y generalmente consecutivos). Para crear un campo con valores autoincrementales, por ejemplo, se utiliza un generador en combinación con un trigger que se ejecute cada vez que se inserta un registro. De esta manera, cada vez que se inserta un nuevo registro, el trigger toma el siguiente valor del generador y lo coloca en el campo autoincremental.

Transacciones

Las transacciones son elementos muy importantes en las bases de datos. Permiten controlar la concurrencia en los accesos y modificación de los datos ya que una transacción es una unidad atómica. Cada vez que un usuario acceda alguna tabla o procedimiento de la base de datos, debe de abrir una transacción para lograr el acceso. Cuando se modifican varias tablas dentro de una transacción, se aplicarán todos los cambios al confirmar la transacción (commit) o se desharán los cambios si ésta se cancela (rollback).

Llave primaria

Aunque este concepto sea conocido para algunos desarrolladores, hay otros que lo desconocen debido a que lo llaman de otra manera o simplemente no lo utilizan. Una llave primaria está compuesta por una o más columnas (campos) de una tabla que tengan valores únicos para cada registro. Cuando creamos una tabla en Firebird/InterBase, es necesario que definamos cuál o cuales columnas serán las que conformen la llave primaria. Hay veces en que aunque no contemos con campos que tengan valores únicos, debemos crear una llave primaria utilizando un campo de autoincremento, implementado mediante un trigger y un generador.

Vistas

Las vistas son tablas "virtuales" creadas a partir de las tablas de la base de datos. Permiten definirlas a partir de una consulta SQL donde se especifican un subconjunto de columnas de la tabla, o bien mediante la unión de tablas (joins) que estén relacionadas por uno o más campos.

El cliente de Firebird/InterBase

Todo aquel que utilice un programa cliente sobre Windows necesita tener instalado en su computadora el cliente de Firebird/InterBase, el cual es un archivo DLL que permite la conectividad entre el programa cliente (escrito generalmente con Delphi/C++Builder) y la base de datos. Este programa cliente se incluye en las distribuciones de Firebird/InterBase para Windows y también se puede obtener como una instalación separada que incluye las herramientas de mantenimiento -como IBConsole- y herramientas de mantenimiento de línea de comandos -como GBAK o GFIX

Dialectos de SQL

Cuando se desarrolló la versión 6 de Firebird/InterBase, se introdujeron algunas mejoras en la definición de algunos tipos de datos y en algunas instrucciones de SQL. Debido a esto, se crearon los dialectos de SQL para mantener compatibilidad con programas clientes de versiones anteriores de Firebird/InterBase. Las versiones anteriores a Firebird/InterBase 6 utilizan el dialecto 1, mientras que Firebird/InterBase 6 puede utilizar ambos dialectos (1 y 3). Se recomienda utilizar el dialecto 3 para tener un máximo aprovechamiento de las nuevas características de Firebird/InterBase 6.

Conceptos de optimización cliente/servidor

Cuando desarrollamos un sistema con Firebird/InterBase, debemos tener en cuenta los conceptos que ya he explicado en este artículo, y utilizar correctamente los recursos que nos permitan tener un buen desarrollo cliente/servidor: Por ejemplo: a) -Cuando se desee mostrar información de alguna tabla o vista, tratar de obtener (seleccionar) solamente los registros que se utilizarán o se visualizarán. Para dar un ejemplo de lo que nunca hay que hacer, mencionaré que si tenemos una tabla con varios cientos o miles de registros, jamás deberemos ejecutar una instrucción como esta: SELECT * FROM TABLA pues esta consulta hará que el programa cliente pida al servidor Firebird/InterBase todos los registros y eso llevará varios minutos e incluso horas en ejecutarse, por lo que no conviene hacerlo. En realidad esta situación se ha optimizado y el servidor no manda todos los registros inmediatamente, pero puede llegar a mandarlos todos si solicitamos ver el último registro de la consulta. b) Utilizar las capacidades del SQL para actualizar valores en alguna tabla de la base de datos. Si uno ha programado con un manejador de base de datos como dBase o Clipper, se está acostumbrado a recorrer cada registro y realizar la actualización de cada uno. Dado que SQL es un lenguaje que trabaja con conjuntos de datos, podemos ejecutar una orden como esta: UPDATE TABLE SET VALOR=VALOR + 1 WHERE CLAVE<100 Y con esta única orden se actualizarán todos aquellos registros cuya clave sea menor a 100. Rápido y sencillo. c) Aprovechar los triggers y los procedimientos almacenados. Hay veces que colocamos en el código de nuestros programas Delphi/C++ Builder las reglas del negocio del sistema. Por ejemplo, si nuestro sistema requiere que se actualicen los valores de una tabla con los totales de otra tabla, tenemos que utilizar el evento BeforePost o AfterPost de nuestro componente Table o Query, y ahí actualizar la otra tabla mediante otro componente Table. Si esto lo pasamos a nivel del servidor con un simple trigger actualizaremos la tabla y quitaremos el código del programa en Delphi/C++ Builder. Los procedimientos almacenados también ayudan a eliminar código de los programas cliente, además de que la información no debe de viajar por la red hasta el cliente. También son muy útiles para crear complejos reportes (informes) que requieran de información distribuida en varias tablas o con condiciones especiales.