OVH Community, your new community space.

Rendimiento mysql con sentencias complicadas


xico1984
12/10/2009, 12:17
Cita Publicado inicialmente por a-n-t-o-n-i-o
como ya te dijeron lo mas rapido es INNER JOIN, y si tus relaciones tienen el mismo nombre en una tabla que en la otra, lo mejor es INNER JOIN tabla USING columna

ejemplo..
(ya sabes en la tabla anuncios y la tabla provincias debe existir idprovincia)

...FROM anuncios INNER JOIN (provincias) USING (idprovincia)

si no tienes la relacion que recomiendo, cambias USING por ON y pones despues el tipico xxxx=yyyyy
Tendré que repasar seriamente los apuntes de la uni jajaj Lo del join (Por la derecha, por la izquierda, etc, etc) es lo que menos pudimos tocar, pero había unos manuales buenísimos. Y así podré hacer las pruebas de rendimiento pertinentes.

Gracias antonio!!

xico1984
12/10/2009, 12:12
Cita Publicado inicialmente por SwaT
El Rendimiento con JOIN (aunque sea implicito) será mejor que con una subconsulta, por lo tanto has de evitar hacer subconsultas (a veces no se puede o es demasiado complicado).

Despues lo que te ha comentado Power de mirar lo que tardan es una buena forma, pero has de tener en cuenta que MySQL suele cachear las tablas una vez ejecutas una query y la segunda ejecución es más rapida (aunque no sea exactamente la misma query, solo con que toque las mismas tablas ya se nota), con lo cual para que sea fidedigno tendrás que vaciar la cache antes de cada query y hacer varias veces los tests para sacar el promedio.

Y por ultimo es un detalle tonto, pero te puedes ahorrar de escribir bastante asignando alias a las tablas, ejemplo:

Código:
SELECT g.id_grupo, g.id_usuario, g.nombre_grupo, ag.id_grupo, ag.id_amigo, u.id_usuario, u.nombre, u.apellidos
FROM
grupos g, amigos_grupos ag, usuarios u
WHERE
u.id_usuario = ag.id_amigo AND
ag.id_grupo = g.id_grupo AND
g.id_grupo = 3 AND
g.id_usuario = 500
Sencillamente le dices que tal tabla se llamara 'x' y puedes usar ese nombre más corto en la query.

Saludos
Muy buen apunte lo de la caché SwaT. Ahora ya se porqué da valores tan dispares :P
Sobre lo de los alias, no lo utilizo, mas que nada cuando tengo algún error y busco entre cientos de funciones un nombre de tabla en concreto, prefiero que aparezca el nombre original :-)

Gracias por la ayuda! ;-)

a-n-t-o-n-i-o
11/10/2009, 13:02
Cita Publicado inicialmente por xico1984

SELECT grupos.id_grupo, grupos.id_usuario, grupos.nombre_grupo, amigos_grupos.id_grupo, amigos_grupos.id_amigo, usuarios.id_usuario, usuarios.nombre, usuarios.apellidos
FROM
grupos, amigos_grupos and usuarios
WHERE
usuarios.id_usuario = amigos_grupos.id_amigo AND
amigos_grupos.id_grupo = grupos.id_grupo AND
grupos.id_grupo = 3 AND
grupos.id_usuario = 500

como ya te dijeron lo mas rapido es INNER JOIN, y si tus relaciones tienen el mismo nombre en una tabla que en la otra, lo mejor es INNER JOIN tabla USING columna

ejemplo..
(ya sabes en la tabla anuncios y la tabla provincias debe existir idprovincia)

...FROM anuncios INNER JOIN (provincias) USING (idprovincia)

si no tienes la relacion que recomiendo, cambias USING por ON y pones despues el tipico xxxx=yyyyy

SwaT
11/10/2009, 11:05
El Rendimiento con JOIN (aunque sea implicito) será mejor que con una subconsulta, por lo tanto has de evitar hacer subconsultas (a veces no se puede o es demasiado complicado).

Despues lo que te ha comentado Power de mirar lo que tardan es una buena forma, pero has de tener en cuenta que MySQL suele cachear las tablas una vez ejecutas una query y la segunda ejecución es más rapida (aunque no sea exactamente la misma query, solo con que toque las mismas tablas ya se nota), con lo cual para que sea fidedigno tendrás que vaciar la cache antes de cada query y hacer varias veces los tests para sacar el promedio.

Y por ultimo es un detalle tonto, pero te puedes ahorrar de escribir bastante asignando alias a las tablas, ejemplo:

Código:
SELECT g.id_grupo, g.id_usuario, g.nombre_grupo, ag.id_grupo, ag.id_amigo, u.id_usuario, u.nombre, u.apellidos
FROM
grupos g, amigos_grupos ag, usuarios u
WHERE
u.id_usuario = ag.id_amigo AND
ag.id_grupo = g.id_grupo AND
g.id_grupo = 3 AND
g.id_usuario = 500
Sencillamente le dices que tal tabla se llamara 'x' y puedes usar ese nombre más corto en la query.

Saludos

xico1984
10/10/2009, 16:37
Cita Publicado inicialmente por Raul
Hola, en principio como ya te comenta Thyng debes familiarizarte con "explain" es una buena forma de comprobar los tipos de consultas realizadas junto a sus posibles "defectos".

Por otra parte, si relacionas varias tablas entre si para obtener muchos datos, lo mejor es utilizar JOIN, es más óptimo. En tu caso prueba con INNER JOIN para los indices, y WHERE ponlo en "id_grupo = 3 AND usuario = 500".

Saludos.
Uhm no había caido con lo del inner join, como no lo he tocado mucho :P

Gracias a los 2 por vuestra ayuda

PD: Y perdón por el retraso!

Raul
22/09/2009, 16:20
Hola, en principio como ya te comenta Thyng debes familiarizarte con "explain" es una buena forma de comprobar los tipos de consultas realizadas junto a sus posibles "defectos".

Por otra parte, si relacionas varias tablas entre si para obtener muchos datos, lo mejor es utilizar JOIN, es más óptimo. En tu caso prueba con INNER JOIN para los indices, y WHERE ponlo en "id_grupo = 3 AND usuario = 500".

Saludos.

Thyng
21/09/2009, 22:58
Prueba con explain

http://dev.mysql.com/doc/refman/5.0/es/explain.html

xico1984
18/09/2009, 14:47
Cita Publicado inicialmente por Power
Hola,

No soy un experto en MySQL, pero creo que, normalmente, es más eficiente utilizar un select con las 3 tablas relacionadas que bucles con selects anidados.

Pero tú mismo puedes comprobarlo.
Si tienes phpMyAdmin, entras en la pestaña SQL, pones el select y lo ejecutas.
Te dará el tiempo que ha tardado.
Y así puedes comparar.

Y, por supuesto, para que las búsquedas sean rápidas, lo más importante es crear índices con los campos que utilizarás en el where.

Saludos.
PD: Que me perdonen los grandes maestros de MySQL, pero soy un pobre autodidacta en el tema y sólo cuento mi experiencia en el tema.
Uhmm si que es verdad, que te da el tiempo que tarda en ejecutar la sentencia... Voy a probarlo :P

Sobre lo de los índices en las búsquedas lo sé jeje Aunque no noté mucha diferencia con una tabla que tengo 1.000.000 de registros, la verdad... Pero claro, puede que la cosa cambie cuanto tenga muchísimas peticiones ^^

Gracias power, todo consejo es bienvenido!!

Power
18/09/2009, 14:27
Hola,

No soy un experto en MySQL, pero creo que, normalmente, es más eficiente utilizar un select con las 3 tablas relacionadas que bucles con selects anidados.

Pero tú mismo puedes comprobarlo.
Si tienes phpMyAdmin, entras en la pestaña SQL, pones el select y lo ejecutas.
Te dará el tiempo que ha tardado.
Y así puedes comparar.

Y, por supuesto, para que las búsquedas sean rápidas, lo más importante es crear índices con los campos que utilizarás en el where.

Saludos.
PD: Que me perdonen los grandes maestros de MySQL, pero soy un pobre autodidacta en el tema y sólo cuento mi experiencia en el tema.

xico1984
18/09/2009, 12:00
Hola gente!

Como aquí hay muchos expertos en muchos ámbitos, seguro que habrán bastantes que puedan saber de este tema.. jejej
Bueno allá voy, estoy en un proyecto que estoy intentando hacerlo lo más seguro posible, pero a su vez quiero que sea lo más eficiente posible.
Va a estar tirando muchísimo de mysql, y tiene miles de sentencias sql. Tiene muchísimas más de selects, pero también tiene bastantes inserts y updates.

El caso es que anteriormente siempre he ido a lo más fácil, hacer selects de los sencillos. Ej:
select campo1,campo2,campo3from unatabla where campo1=dato1

Pero al estar haciendo una aplicación bastante mas larga, y completa a veces veo la necesidad de utilizar (o es más cómo para mi) subselects (not in, etc), productos cartesianos con muchas tablas implicadas, etc.

Todas estas subselects, productos cartesianos, y demás se podrían utilizar con varios selects sencillos, y unidos con bucles, pero no estoy seguro que sería mas eficiente...

Para que os hagáis una idea, tengo unas 50 tablas, de las que unas 15 se relacionan entre ellas, pero con un nivel máximo de 5 relaciones entre ellas. Lo normal, son relaciones entre 2 o 3 tablas. Uno de esas tablas será la que más carga tendrá, al tener los datos de los usuarios.

Os voy a poner un ejemplo para que sepáis a que me refiero. Tengo una tabla con grupos que puede tener cada usuario grupos(id_grupo,id_usuario,nombre_grupo), otra tabla con los usuarios apuntados a cada grupo amigos_grupos(id_grupo,id_amigo). Y otra tabla con los datos de usuarios usuarios(id_usuario,nombre,apellidos)

Necesito sacar el nombre y apellidos de los miembros del grupo 3 del usuario 500. Puedo hacerlo sacando las 3 tablas al mismo tiempo, relacionándolas entre ellas, o bién sacar primero GRUPOS y AMIGOS_GRUPOS en la misma select, y luego conforme me va sacando el id de cada amigo, ir sacando con otra select, los datos de la tabla USUARIOS.

Ejemplo de la sentencia más completa:

SELECT grupos.id_grupo, grupos.id_usuario, grupos.nombre_grupo, amigos_grupos.id_grupo, amigos_grupos.id_amigo, usuarios.id_usuario, usuarios.nombre, usuarios.apellidos
FROM
grupos, amigos_grupos and usuarios
WHERE
usuarios.id_usuario = amigos_grupos.id_amigo AND
amigos_grupos.id_grupo = grupos.id_grupo AND
grupos.id_grupo = 3 AND
grupos.id_usuario = 500


grupos.id_usuario = 500 Es redundante, porque antes tengo otra sentencia que me saca los grupos que tiene el usuario 500. Así que únicamente lo utilizo para VERIFICAR que ese grupo es el legítimo del usuario que está conectado a su cuenta de administrator. Por si intentan hacerme la pirula, y quieren ver los grupos de otro usuario...

¿Qué os parece? Mejor 3 sentencias seguidas y relacionadas? O 2 sacando los grupos, los miembros de los grupos, y luego conforme voy teniendo el id_amigo, voy sacando los datos con otra select?

SELECT usuarios.id_usuario, usuarios.nombre, usuarios.apellidos
FROM usuarios
WHERE
usuarios.id_usuario = X

Sería fantástico que alguien pudiera echarme un cable.... Os lo agradecería un montóoooon