Novedades en InterBase 6.5
En el momento en que redacto este truco, InterBase 6.5 tiene algunas semanas de vida. Hace unos meses, publiqué un par de advertencias sobre problemas existentes en InterBase 6.01, con el título Problemas con InterBase. La nueva versión resuelve varios de esos problemas, y ha añadido nuevas características que mejoran considerablemente el producto.
TRANSMISION EFICIENTE DE REGISTROS
A partir de InterBase 6.5, cuando se transmite una columna de tipo varchar, sólo se transmiten los caracteres realmente almacenados en cada fila. Si ha declarado que la columna Nombre pertenece al tipo varchar(35), y en el registro que va a transmitir el servidor de InterBase, esa columna contiene "Pepe", se transmitirán los cuatro bytes del valor, más algún tipo de indicación sobre el tamaño, ya sea un terminador, o la longitud de la cadena. Antes, por el contrario, se pasaban los 35 caracteres definidos estáticamente.
¿Cómo es posible comprobar este tipo de problemas, en general? En el número 59 de
"The Delphi Magazine", correspondiente a julio del 2000, Jani Järvinen describe una herramienta llamada IBSec, que intercepta el tráfico TCP/IP entre un cliente de InterBase y su servidor. La utilidad principal de IBSec es cifrar los paquetes que circulan por la red, pero puede también comprimirlos. Y, por supuesto, espiar qué se envía y recibe en cada momento. Si tiene alguna sospecha de algo "malo" que esté haciendo InterBase a sus espaldas, puede desarrollar una aplicación de este tipo y comprobarlo usted mismo.
EL PROBLEMA DEL SELECT DENTRO DEL PROCEDIMIENTO
Esta es una disgresión, porque se trata de un problema exclusivo de la versión Open Source de InterBase. El problema no se presentaba en la 6.01 certificada, y por supuesto, no existe tampoco en la 6.5. ¿Recuerda que select/into no funcionaba correctamente cuando se almacenaba el valor en un parámetro de retorno de un procedimiento almacenado? Hace una o dos semana, Jorge Ramírez Baños, un estudiante de Informática mexicano, me comunicaba un truco que puede resolver el problema. Consiste en incluir una instrucción suspend al finalizar el procedimiento:
create procedure CodigoCliente(id integer)
returns (nombre varchar(30)) as
begin
select Nombre
from CLIENTES
where IdCliente = :ID
into :nombre;
suspend; /* Este es el truco */
end
Sigue existiendo el error, porque ese suspend no debería ser obligatorio, pero al menos sirve para controlar los daños provocados por el bug.
LA CLAUSULA ROWS
Para el tipo de aplicaciones con las que estoy trabajando, la novedad más importante es la cláusula rows, que sirve para limitar el número de registros devueltos por una consulta. Observe la siguiente instrucción:
select (select sum(ItemsTotal)
from Orders ord
where ord.CustNo = cust.CustNo) total, cust.*
from CUSTOMER cust
order by 1 desc
rows 10
La instrucción anterior devuelve registros de clientes asociados con la suma de los importes de sus pedidos. El resultado se ordena de mayor a menor por la suma de los importes... pero solamente se envían al cliente los diez primeros registros. ¿Resultado? Para empezar, menos tráfico en red. Es posible también, en dependencia del plan de ejecución, que se ahorre algún tiempo en la evaluación. La petición se atiende también en menos tiempo, y eso libera los recursos necesarios con mayor rapidez; algo muy importante si se está usando un servidor de capa intermedia.
Note que en el ejemplo se utiliza rows en paralelo con una ordenación. No se trata de algo estrictamente necesario, pero la ordenación garantiza que la cláusula tenga un significado práctico. Compare con la forma que tiene Oracle de lograr el mismo propósito con la seudo columna rownum: como ésta se evalúa antes de la ordenación, la utilidad práctica casi desaparece.
Debe saber también que la cláusula admite unas cuantas opciones más: es posible indicar un porcentaje del total, iniciar la devolución de filas por una fila que no sea la primera, escoger una fila de cada tantas, incluir los "empates" (opción with ties)... Además, y esta es el desvío más importante respecto al estándar SQL por parte de InterBase, se puede utilizar order by y rows en borrados y actualizaciones. Por ejemplo:
delete from EMPLOYEE
order by Salary desc
rows 1
Quiero dejar claro que veo muy bien que se viole el "estándar" si es para mejorar el lenguaje. De todos modos, es un estándar que nadie respeta ya.
MAS CAMBIOS
Hay un cambio que va a tener más repercusiones de las que imaginaron en el equipo de desarrollo de InterBase: ahora es posible restringir el acceso a las tablas de sistema. Esto, en sí, es una buena noticia: impide que un usuario idiota fastidie una base de datos, y evita que un programador poco escrupuloso pueda copiar impunemente el código fuente de nuestros triggers y procedimientos almacenados. Pero puede tener repercusiones negativas para las aplicaciones que utilizaban trucos con las tablas de sistemas para suplir carencias en InterBase. Por ejemplo, a estas alturas todavía no existe una sentencia drop generator, y para eliminar un generador hay que borrarlo directamente de la tabla de sistema correspondiente. Sin embargo, el truco más extendido con las tablas de los sistemas es el que nos permite obtener el valor actual de un generador en una base de datos arbitraria:
select gen_id(nombreGenerador, 0)
from RDB$DATABASE
Este truco se basa en que RDB$DATABASE es una tabla de sistema que tiene siempre una sola fila, y es utilizado incluso por InterBase Express. Ahora imagine la que se puede liar si alguien decide impedir el acceso a esta tabla...
InterBase 6.5 ha añadido, además, soporte para ficheros de más de 4GB, ha mejorado el manejo de la memoria caché, ha añadido funciones al API para generar XML directamente y para cancelar instrucciones de forma asíncrona. Finalmente, ahora existe una opción para "atar" el código del servidor a un procesador específico en máquinas con varios procesadores, para evitar la descomunal pérdida de eficiencia que se presentaba en esos casos. Se trata, por supuesto, de una medida temporal hasta que se introduzca soporte específico para multiprocesamiento simétrico en una futura versión.
|