SQL - Duda rendimiento MySQL

 
Vista:

Duda rendimiento MySQL

Publicado por nifff (2 intervenciones) el 10/12/2015 10:43:01
Tengo una duda de rendimiento en sql, estoy ejecutando la consulta descrita abajo.
Hago varios left joins, con tablas que tienen algunas de ellas un numero muy elevado de registros para luego hacer un grouo by - count.

Las tablas de los joins, por ejemplo la de estadisticas_banners (guardamos informacion sobre que usuarios ha hecho click en que banners) tienen la siguiente estructura:
id, id_banner, id_usuario.

En este caso, a mi solo me interesa el total, ¿Mejoraría el rendimiento si en vez de hacer un count y un group by crease una vista con la siguiente estructura para hacer el join con ésta?:
id, id_usuario, total_banners_clickados.

Gracias!

1
2
3
4
5
6
7
8
Select users.nombre, apellidos, email , count(distinct ep.id) as paginas_visitadas, count(distinct eb.id) as banners_clickados, count(distinct ficheros.id) as ficheros_subidos, count(distinct mensajes.id) as mensajes_enviados, count(distinct messages.id) as chats_enviados
from users
left join estadisticas_pagina ep on ep.user_id = users.id
left join estadisticas_banner eb on eb.user_id = users.id
left join ficheros on ficheros.subido_por = users.id
left join mensajes on mensajes.enviado_por = users.id
left join messages on messages.sender_id = users.id
where 1 = 1 and (ep.created_at between '2015-01-01' and '2015-12-10' or ep.created_at IS NULL) and (eb.created_at between '2015-01-01' and '2015-12-10' or eb.created_at IS NULL) and (ficheros.created_at between '2015-01-01' and '2015-12-10' or ficheros.created_at IS NULL) and (mensajes.created_at between '2015-01-01' and '2015-12-10' or mensajes.created_at IS NULL) and (messages.created_at between '2015-01-01' and '2015-12-10' or messages.created_at IS NULL) group by nombre, email, apellidos
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder
sin imagen de perfil
Val: 109
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

Duda rendimiento MySQL

Publicado por Rafael (111 intervenciones) el 10/12/2015 11:05:54
OJO, las vistas no mejoran performance, solo te ahorran tiempo de codificacion, la vista no tiene datos guardados salvo que sea materializada...

Una vista materializada no te da resultados en tiempo real, y si la tienes que refrescar cada que consultes no te dara lo que buscas...

De primeras los pasos van por crear indices por ID_USUARIO y las fechas CREATED_AT en cada una de las tablas que haces JOIN, no obstante aqui surge otro problema estos indices no se veran realmente aprovechados ya que usas un LEFT JOIN ...

Estos indices deberian ayudar algo y quizas probar la consulta de este modo...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
SELECT users.nombre
	 , apellidos
	 , email
	 , (SELECT count(DISTINCT ep.id)
        FROM   estadisticas_pagina ep
        where  ep.user_id = users.id
        AND    (   ep.created_at BETWEEN '2015-01-01' AND '2015-12-10'
                OR ep.created_at IS NULL))
       AS paginas_visitadas
	 , (SELECT count(DISTINCT eb.id)
        FROM   estadisticas_banner eb
        WHERE  eb.user_id = users.id
        AND    (   eb.created_at BETWEEN '2015-01-01' AND '2015-12-10'
                OR eb.created_at IS NULL))
       AS banners_clickados
	 , (SELECT count(DISTINCT ficheros.id)
        FROM   ficheros
        WHERE  ficheros.subido_por = users.id
	    AND    (   ficheros.created_at BETWEEN '2015-01-01' AND '2015-12-10'
		        OR ficheros.created_at IS NULL))
       AS ficheros_subidos
	 , (SELECT count(DISTINCT mensajes.id)
        FROM   mensajes
        WHERE  mensajes.enviado_por = users.id
        AND    (   mensajes.created_at BETWEEN '2015-01-01' AND '2015-12-10'
                OR mensajes.created_at IS NULL))
       AS mensajes_enviados
	 , (SELECT count(DISTINCT messages.id)
        FROM   messages
        WHERE  messages.sender_id = users.id
        AND    (   messages.created_at BETWEEN '2015-01-01' AND '2015-12-10'
                OR messages.created_at IS NULL))
       AS chats_enviados
FROM users

Asi si que forzarias la utilizacion de los indices y no pasarias por el GROUP BY, lo cual te debe mejorar en algo la consulta.

Saludos

Pd. Si esto te sirve a mi me sirve un +1
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
sin imagen de perfil

Duda rendimiento MySQL

Publicado por nifff (3 intervenciones) el 10/12/2015 11:43:51
Ha mejorado muchísimo el rendimiento con tu consulta sin la necesidad de usar índices. ¡Muchas gracias!

¿Podrías explicación teórica muy rápida de por que este modo de realizar la consulta mejora tanto el rendimiento?

Un saludo!
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 109
Ha mantenido su posición en SQL (en relación al último mes)
Gráfica de SQL

Duda rendimiento MySQL

Publicado por Rafael (111 intervenciones) el 10/12/2015 14:15:45
Primero por que calculas uno a uno los totales de los usuarios sin forzar a que los ordene y despues los agrupe... me explico...

Cuando tu haces un
1
2
3
4
SELECT <agrupador>
     , SUM(<algo>)
FROM   <Tabla>
GROUP  BY <agrupador>
lo primero que hacen las bases de datos es obtener todos los datos, luego los ordena y finalmente los agrupa...

Los procesos de ordenacion y agrupacion le son costosos y requiere uso de memoria pero sobre todo de CPU.

Cuando lo haces mediante "Queries correlativas" te ahorras el ordenamiento y la agrupacion

En el caso de tu consulta la original sigue el siguiente plan:
1. Va por todos los usuarios (sin importar el orden)
2. Añada los registros que va a sumar de cada tabla en el join.
3. Ordena la informacion.
4. Agrupa para totalizar.

En la consulta propuesta:
1. Va por todos los usuarios (sin importar el orden)
2. Totaliza solo para cada usuario los registros en cada tabla destino.

El hacer 2 pasos siempre sera mas rapido que 4.

Ahora bien si pones los indices que te he indicado la consulta debera ir aun mas rapido por que al totalizar para cada usuario podra acceder aun mas rapido a dichos resultados.

Saludos

Pd. Si esto te sirve a mi me sirve un +1
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
2
Comentar
sin imagen de perfil

Duda rendimiento MySQL

Publicado por Javier (3 intervenciones) el 10/12/2015 14:36:27
Gracias por la solución y la explicación

Un abrazo!
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar