Foros del Web » Programación para mayores de 30 ;) » Bases de Datos General » Mysql »

Optimizar consulta

Estas en el tema de Optimizar consulta en el foro de Mysql en Foros del Web. Hola a todos Nuevamente recurriendo a su ayuda. Tengo este codigo, que recoge datos de 6 tablas distintas que están en 3 bases, ubicadas en ...
  #1 (permalink)  
Antiguo 15/05/2009, 06:27
 
Fecha de Ingreso: abril-2008
Mensajes: 208
Antigüedad: 16 años
Puntos: 2
Optimizar consulta

Hola a todos
Nuevamente recurriendo a su ayuda.
Tengo este codigo, que recoge datos de 6 tablas distintas que están en 3 bases, ubicadas en un mismo host. La consulta la tengo dentro de un SP para entregar solo el "Call" a la aplicación cliente.
Bien la consulta en sí se ejecuta bien (levanta los datos) pero demora 35 segundos en hacerlo.
MI pregunta es como podría mejorar este tiempo

Desde ya gracias

Código:
DELIMITER $$

DROP PROCEDURE IF EXISTS `rrserver`.`Informe Agentes`$$

CREATE DEFINER=`root`@`%` PROCEDURE `Informe Agentes`(inicio datetime, 
                                                         fin datetime,
                                                      estado varchar(15),
                                                   empleador varchar(20),
                                                       cargo varchar(15))
BEGIN
Select
u.nombreapellido NOMBRE,
u.portalid USERPORTAL,
m.tipo_turno `TIPO TURNO`,
IFNULL((
        SELECT COUNT(c.numero_consulta)
        FROM portalreflex.consultas c
        WHERE c.usuario_ingreso = u.portalid
        AND c.fecha_ingreso between inicio AND fin
        GROUP BY c.usuario_ingreso
        ),0) `CONSULTAS`, /* Ejecuta una  sub consulta a la tabla consultas*/
IFNULL((
        SELECT count(b.usuario_ingreso)
        FROM portalreflex.boletas b
        WHERE b.usuario_ingreso = u.portalid
        AND b.fecha_ingreso between inicio AND fin
        GROUP BY b.usuario_ingreso
        ),0) `BOLETAS`,
IFNULL((
        SELECT COUNT(r.numero_requerimiento)
        FROM portalreflex.requerimientos r
        WHERE r.usuario_ingreso = u.portalid
        AND r.fecha_ingreso between inicio AND fin
        GROUP BY r.usuario_ingreso
        ),0) `REQUERIMIENTOS`,
IFNULL((
        SELECT SUM(t.recibido)
        FROM rrserver.agente_15minutos t
        WHERE t.userid = u.userid
        AND t.fecha between inicio AND fin
        GROUP BY t.userid
        ),0) LLAMADAS
FROM rrserver.usuarios u  
INNER JOIN monitoreo.agentes m
ON u.userid = m.userid
WHERE m.estado LIKE estado
AND m.empleador_agente LIKE  empleador
AND m.cargo LIKE cargo
GROUP BY u.userid
ORDER BY u.nombreapellido asc;   
    END$$

DELIMITER ;

PD: una pregunta al margen, como lo hacen para etiquetar codigos sql en el foro ???
  #2 (permalink)  
Antiguo 15/05/2009, 07:01
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Optimizar consulta

Pruebalo de esta forma:
Código sql:
Ver original
  1. DELIMITER $$
  2.  
  3. DROP PROCEDURE IF EXISTS `rrserver`.`Informe Agentes`$$
  4.  
  5. CREATE PROCEDURE `Informe Agentes`(
  6.   inicio    datetime,
  7.   fin       datetime,
  8.   vestado    VARCHAR(15),
  9.   empleador VARCHAR(20),
  10.   vcargo     VARCHAR(15))
  11. BEGIN
  12.   SELECT
  13.     u.nombreapellido NOMBRE,
  14.     u.portalid USERPORTAL,
  15.     m.tipo_turno `TIPO TURNO`,
  16.     SUM(IF(c.numero_consulta IS NULL, 0, 1)) `CONSULTAS`,
  17.     SUM(IF(b.usuario_ingreso IS NULL, 0, 1)) `BOLETAS`,
  18.     SUM(IF(r.numero_requerimiento IS NULL, 0, 1)) `REQUERIMIENTOS`,
  19.     SUM(IF(t.recibido IS NULL, 0, 1)) `LLAMADAS`
  20.   FROM rrserver.usuarios u
  21.     INNER JOIN monitoreo.agentes m USING(userid)
  22.     LEFT JOIN portalreflex.consultas c ON c.usuario_ingreso = u.portalid
  23.     LEFT JOIN portalreflex.requerimientos r ON r.usuario_ingreso = u.portalid
  24.     LEFT JOIN rrserver.agente_15minutos t ON
  25.   WHERE
  26.     m.estado LIKE vestado AND
  27.     m.empleador_agente LIKE  empleador AND
  28.     m.cargo LIKE vcargo
  29.   GROUP BY u.userid
  30.   ORDER BY u.nombreapellido ASC;
  31. END$$
  32.  
  33. DELIMITER ;

El problema que tienes es que cada subconsulta en el SELECT se ejecuta una vez por cada campo y por cada registro, de modo que si tienes 5000 registros, esos select corren 20.000 veces en una sola ejecución. No es eficiente.

Tips:
1. No pongas los mismos nombres en las variables que en los campos que usas. Esto puede confundir al parser de MySQL y dar lugar a errores porque MySQL prioriza los campos y las tablas por sobre las variables.
2. La respuesta a tu pregunta del código está en : Nuevo resaltador de código Geishi - Foros del Web
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #3 (permalink)  
Antiguo 15/05/2009, 08:55
 
Fecha de Ingreso: abril-2008
Mensajes: 208
Antigüedad: 16 años
Puntos: 2
Respuesta: Optimizar consulta

Gracias gnzsoloyo por la rapida ayuda.

Te cuento, del codigo que me diste agregue un par de lineas por que me daba error:
1. los valores del ON : LEFT JOIN rrserver.agente_15minutos t ON
2. y agregue : LEFT JOIN portalreflex.boletas b ON b.usuario_ingreso = u.portalid

pero al ejecutar la consulta se queda eternamente ahí. Revisé en el servidor con el MySql administrator y la consulta efectivamente ocupa menos recursos que la anterior, pero por alguna razón no devuelve los datos, finalmente la tengo que bajar.

Código MySql:
Ver original
  1. DELIMITER $$
  2. DROP PROCEDURE IF EXISTS `rrserver`.`Informe Agentes2`$$
  3. CREATE PROCEDURE `Informe Agentes2`(  
  4. inicio    datetime,  
  5. fin       datetime,  
  6. vestado    varchar(15),  
  7. empleador varchar(20),  
  8. vcargo     varchar(15))
  9. SELECT    
  10. u.nombreapellido NOMBRE,    
  11. u.portalid USERPORTAL,    
  12. m.tipo_turno `TIPO TURNO`,    
  13. sum(IF(c.numero_consulta IS NULL, 0, 1)) `CONSULTAS`,    
  14. sum(IF(b.usuario_ingreso IS NULL, 0, 1)) `BOLETAS`,    
  15. sum(IF(r.numero_requerimiento IS NULL, 0, 1)) `REQUERIMIENTOS`,    
  16. SUM(IF(t.recibido IS NULL, 0, 1)) `LLAMADAS`  
  17. FROM rrserver.usuarios u    
  18. INNER JOIN monitoreo.agentes m
  19. USING(userid)    
  20. LEFT JOIN portalreflex.consultas c ON c.usuario_ingreso = u.portalid  
  21. LEFT JOIN portalreflex.boletas b ON b.usuario_ingreso = u.portalid  
  22. LEFT JOIN portalreflex.requerimientos r  ON r.usuario_ingreso = u.portalid    
  23. LEFT JOIN rrserver.agente_15minutos t ON  t.userid = m.userid
  24. WHERE m.estado LIKE vestado
  25. AND m.empleador_agente LIKE empleador
  26. AND m.cargo LIKE vcargo  
  27. GROUP BY u.userid  
  28. ORDER BY u.nombreapellido ASC;
  29. END$$
  30. DELIMITER ;

Como siempre muchas gracias por la ayuda
  #4 (permalink)  
Antiguo 15/05/2009, 09:01
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Optimizar consulta

Si eso es lo que sucede, entonces lo que hay que hacer es probar en forma segmentaria los JOIN de a uno y ver cuál es la combinacion que produce el problema.
Mas tarde veo bien otra posibilidad y te la paso.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #5 (permalink)  
Antiguo 19/05/2009, 16:00
 
Fecha de Ingreso: abril-2008
Mensajes: 208
Antigüedad: 16 años
Puntos: 2
Respuesta: Optimizar consulta

Hola Retomando el tema

Hice las pruebas y definitivamente la consulta funciona con un solo join, cualquiera. Al adicionar otro ya se cuelga y no va a ningun lado.

Desde ya gracias por la ayuda
  #6 (permalink)  
Antiguo 20/05/2009, 05:17
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Optimizar consulta

¿Con cuál JOIN Funciona?
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #7 (permalink)  
Antiguo 20/05/2009, 06:11
 
Fecha de Ingreso: abril-2008
Mensajes: 208
Antigüedad: 16 años
Puntos: 2
Respuesta: Optimizar consulta

Hola Gnzsoloyo

Con todos los join por separado, al juntar 2 ya no corre

Chelodelsur
  #8 (permalink)  
Antiguo 20/05/2009, 07:39
Avatar de gnzsoloyo
Moderador criollo
 
Fecha de Ingreso: noviembre-2007
Ubicación: Actualmente en Buenos Aires (el enemigo ancestral)
Mensajes: 23.324
Antigüedad: 16 años, 4 meses
Puntos: 2658
Respuesta: Optimizar consulta

¿No corre, o no devuelve datos?
Si no devuelve datos, es que no hay datos que puedan cumplir exactamente con los JOIN, o una condición INNER JOIN está devolviendo NULL.
Si corre demasiado tiempo, es que estás construyendo un producto cartesiano y el resultado es demasiado grande. Debes aumentar la selectividad, o bien crear tablas en memoria para el filtrado intermedio de datos. En este caso usa EXPLAIN para que te haga un análisis de la ejemcución y verás donde está el problema.
__________________
¿A quién le enseñan sus aciertos?, si yo aprendo de mis errores constantemente...
"El problema es la interfase silla-teclado." (Gillermo Luque)
  #9 (permalink)  
Antiguo 20/05/2009, 08:09
 
Fecha de Ingreso: abril-2008
Mensajes: 208
Antigüedad: 16 años
Puntos: 2
Respuesta: Optimizar consulta

Eso es lo que pasa. se queda tratando de sacar el resultado, pero finalmente tengo que parar la consulta antes que me vote el servidor.
Cita:
Si corre demasiado tiempo, es que estás construyendo un producto cartesiano y el resultado es demasiado grande
Disculpa la ignorancia, pero como hago un explain??
Cita:
En este caso usa EXPLAIN para que te haga un análisis de la ejemcución y verás donde está el problema.
esto me dá la sentencia

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE m ALL \N \N \N \N 91 Using where; Using temporary; Using filesort
1 SIMPLE u eq_ref PRIMARY PRIMARY 4 monitoreo.m.userid 1
1 SIMPLE c ALL \N \N \N \N 25263
1 SIMPLE b ALL \N \N \N \N 40166
1 SIMPLE r ALL \N \N \N \N 25911
1 SIMPLE t ALL \N \N \N \N 28198

Uf me queda desordenado la tabla (como puedo cargar eso de mejor manera al foro??)
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 08:03.