PDA

Ver la Versión Completa : Procedure en Firebird lento o IbQuery lento


capo979
16-07-2007, 14:24:03
Hola que tal? tengo un store procedure que trae los datos de personas de una tabla y muestra también datos de otras tablas. Esto lo hago con un store procedure. Y lo muestro en delphi 7 en un dbgrid a través de un IBQuery. El tema es que con 200 personas anda joya con 500 también pero ya con 1000 empieza a andar lento y ni les cuento con 10000 personas tarda como 10 segundos y esto parece que sea algo exponencial. La consulta es si saben como mejorar esto dado que me está trayendo muchos dolores de cabeza.

Muchas gracias

Saludos a todos

Neftali [Germán.Estévez]
16-07-2007, 15:50:54
Yo no entiendo mucho de IB/FB, pero por poco que entienda, si no pones la consulta o StoredProc que estás haciendo poco podremos ayudar...

Mick
16-07-2007, 15:57:14
Tienes dos posibilades:

- Que la consulta en si no escale bien (se puede comprobar con ibconsole o ibexpert el tiempo de ejecucion), si es este caso faltaran los indices adecuados en las tablas para acelerarla, o estara mal diseñada y habra que hacer la consulta de otro modo.

-Que la consulte escale bien, pero se tarde demasiado tiempo en recibir la informacion del servidor al cliente, porque la velocidad de la red sea lenta o se traigan demasiados registros de golpe.
En este caso reparar la red local para que vaya a su velocidad, o si se traen demasiados registros de golpe, pues tan sencillo como no recogerlos todos, sino solo aquellos que sean necesario visualizar en cada momento en el ordenador cliente.

Saludos

gabrielkc
16-07-2007, 18:22:33
Que versión usas?

en cualquier caso te recomiendo que cambies a Firebird 2.0. Pero por favor pon más información. La sentencia, que S.O. que versión de Interbase.

10000 registros por si solos no son nada, pero digamos :

Select * from Tabla10000registros, OtraTabla10000registros

además de ser generalmente no necesario es muy ineficiente,

Usar Joins, crear índices, seleccionar SÓLO los campos necesarios es una buena costumbre.

capo979
16-07-2007, 18:24:13
Claro a mi me gustaría saber como hacer para decirle al IBQuery que no me traiga todos los registros sino solamente los que se muestran o los primeros mil .

RolphyReyes
16-07-2007, 19:21:27
Saludos.

Para limitar los registros en Firebird tienes FIRST desde la 1.5.
En Interbase/Firebird tienes SKIP y si no me equivoco creo que desde Interbase 6.5 tienes ROWNUM o ROWS.

Lo que si te aconsejo como lo hicieron anteriormente es que te cambies para Firebird 2.0.

Hasta luego.

capo979
16-07-2007, 19:42:09
Yo tengo los indices creados y utilizo firebird 1.5. El tema es que yo desde el EMS Firebird Manager ejecuto el store procedure y no tarda casi nada y lo hago desde delphi y tarda mucho. Ustedes dicen que con firebird 2.0 anda mejor??

egostar
16-07-2007, 20:13:43
Cuando ejecutas un SP con algún administrador pasas parámetros directamente, pero cuando lo haces con delphi, necesariamente requieres de enviar esos parámetros, me pregunto si no hay alguna rutina que está generando el retrazo que comentas y no necesariamente al ejecutar el SP.

Digo, solo estoy hablando al aire, pero si nos ayudas mostrando lo que estas haciendo sería mucho mejor.

Salud OS.

capo979
16-07-2007, 20:26:12
Hola, lo que tengo dentro del SP un for que recorre un select y dentro de este for hago algunos calculos, pero algo debe estar pasando porque 10000 registros es muy poco

capo979
16-07-2007, 21:01:19
lo que anda lento parece ser es que tengo dentro del for una consulta asi

select max(id) from tabla where (estab = :estab) and (doc = :doc)
into :maxid;

el problema es con el max me parece

que me pueden decir

egostar
16-07-2007, 21:28:55
Yo lo que creo es una combinacion de sentencias la que te hace lenta la consulta, he recreado tu select en una base con 20,000 registros y es de inmediata la respuesta tanto en IBExpert como en Delphi.

Yo insisto en que si no muestras tu SP completo es difícil ayudar, pero noto cierta renuencia de tu parte a hacerlo.

Salud OS.

capo979
16-07-2007, 21:41:22
este es mi SP

CREATE PROCEDURE GEN_ANIMALES (
ESTABLECIMIENTO INTEGER,
ACTUAL DATE,
CON_EVENTO VARCHAR (1) CHARACTER SET NONE)
RETURNS (
ANIMAL INTEGER,
RP VARCHAR (10) CHARACTER SET NONE,
SEXO INTEGER,
RAZA INTEGER,
RAZA_NOMBRE VARCHAR (50) CHARACTER SET NONE,
RODEO INTEGER,
CATEGORIA INTEGER,
CATEGORIA_NOMBRE VARCHAR (50) CHARACTER SET NONE,
CRONO_DENT INTEGER,
ESTADO_REPRO INTEGER,
NACIMIENTO DATE,
EDAD INTEGER,
POTRERO INTEGER,
ACTIVO VARCHAR (1) CHARACTER SET NONE,
COND_CORP INTEGER,
GDR INTEGER,
PESO INTEGER,
RECHAZADO VARCHAR (1) CHARACTER SET NONE,
FRAME FLOAT,
ESTADO_ACTUAL VARCHAR (50) CHARACTER SET NONE,
ULTIMO_EVENTO VARCHAR (255) CHARACTER SET NONE,
EDADCAPTION VARCHAR (12) CHARACTER SET NONE,
ESTADO_LACTACION INTEGER)
AS -- estado_actual, ultimo_evento, datos_eve se deben calcular
declare variable mensaje varchar(50);
declare variable ultimo_eve integer;
declare variable evento varchar(255);

BEGIN
for select ta.id_animal, ta.id_rp, cs.tipo, ta.raza, cr.nombre, ta.rodeo, ta.categoria, cc.nombre,
ta.cronologia_dentaria, ta.estado_reproductivo, ta.fecha_nacimiento, ta.potrero,
ta.activo, ta.condicion_corporal, ta.gdr, ta.peso, ta.rechazado, ta.frame, ta.estado_lactacion
from tab_animales ta, cod_sexos cs, cod_categorias cc, cod_razas cr
where (ta.establecimiento = :establecimiento) and (ta.sexo = cs.id_sexo)
and (ta.raza = cr.id_raza) and (ta.categoria = cc.id_categoria)
into :animal, :rp, :sexo, :raza, :raza_nombre, :rodeo, :categoria, :categoria_nombre, :crono_dent,
:estado_repro, :nacimiento, :potrero, :activo, :cond_corp, :GDR, :peso, :rechazado, :frame, :ESTADO_LACTACION
do
begin
if (:peso is null) then
begin
select first 1 ep.peso from eve_eventos ee, eve_peso ep
where ee.id_evento = ep.id_evento
and ee.animal = :animal
and ee.establecimiento = :establecimiento
order by ee.fecha desc
into :peso;
end

edad = (actual - nacimiento)/365;
if (edad < 2) then
EdadCaption = cast(((actual - nacimiento)/30) as varchar(6))||' meses';
else
EdadCaption = cast(edad as varchar(6))||' años';

-- recupero el estado actual desde el sp genereado para calcular el estado actual
select estado_actual from gen_estado_actual(:animal)
into :estado_actual;

--me fijo si tengo que generar_datos del evento
if (con_evento = 'S') then
begin
select max(id_evento) from eve_eventos where (establecimiento = :establecimiento) and (animal = :animal)
into :ultimo_eve;

select nombretipoevento, infoevento from get_datos_eventos_grupal(:ultimo_eve, null, :establecimiento)
into :evento, :ultimo_evento;

ultimo_evento = evento || ', '||ultimo_evento;
end
SUSPEND;
end
END

si yo comento esto

if (:peso is null) then
begin
select first 1 ep.peso from eve_eventos ee, eve_peso ep
where ee.id_evento = ep.id_evento
and ee.animal = :animal
and ee.establecimiento = :establecimiento
order by ee.fecha desc
into :peso;
end

y esto

select max(id_evento) from eve_eventos where (establecimiento = :establecimiento) and (animal = :animal)
into :ultimo_eve;

anda rápido pero si lo dejo se pone muy lento

tengo todos los indices creados

y utilizo firebird 1.5

Neftali [Germán.Estévez]
17-07-2007, 10:59:13
Una pregunta; ¿Hay alguna razón para no usar JOIN's (INNER sobre todo, -si es posible-) en las consultas y realizar las uniones entre tablas usando los WHERE?

Mick
17-07-2007, 11:25:51
lo que anda lento parece ser es que tengo dentro del for una consulta asi

select max(id) from tabla where (estab = :estab) and (doc = :doc)
into :maxid;

el problema es con el max me parece

que me pueden decir

Por lo ultimo que explicas a mi parecer todo va rapido solo 10 segundos, estas ejecutando un select por cada registro de la sentencia inicial, eso si el sistema, no escalará bien, cuantos mas registros mas selects a realizar y mucho mas lento.

De todas formas es probable que lo puedas acelerar mas: ¿ seguro que tienes creado un indice "DESCENDENTE" para el campo ID de la tabla ?

Un max(ID) para que sea rapido exige un indice DESCENDENTE sobre el campo ID, no sirve la clave primaria ni un indice normal ascendente (estos solo valen para acelerar la funcion MIN).

Asegurate de usar el ibconsole o cualquier otro programa para probar las queries y mirar el tiempo que tardan y el PLAN que se genera para saber si se esta usando algun indice si pone PLAN (TABLA NATURAL) malo malo, no hay ningun indice que se pueda usar para acelerar la consulta.

Saludos

capo979
17-07-2007, 21:35:36
Hago una consulta es posible que en un dbgrid en delphi que tiene asociado un IBQuery no espere a mostrar los datos hasta que termine de cargar los registros.
Por ejemplo tenemos una consulta que la ejecutamos con un IBQuery y esa consulta nos devuelve 30000 registros y el dbgrid no espere a que termine de leer la consulta y que te muestre los que están en pantalla directamente. Si luego navegamos por el dbgrid y bajamos con el scroll ahi si que se actualice. Yo utilizo el EMS como Manager de mi base en firebird y EMS hace esto que digo yo luego que ejecuta una consulta.