Soy muy nuevo en MySQL y gracias al gran apoyo de ustedes muchachos más experimentados aquí estoy logrando luchar, mientras aprendí mucho en el proceso.¿Cómo puedo simplificar/mejorar el rendimiento de esta consulta MySQL?
Tengo una consulta que hace exactamente lo que quiero. Sin embargo, me parece extremadamente desordenado y estoy seguro de que debe haber una forma de simplificarlo.
¿Cómo se puede mejorar y optimizar esta consulta para el rendimiento?
Muchas gracias
$sQuery = "
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM $sTable b
LEFT JOIN (
SELECT COUNT(*) AS projects_count, a.songs_id
FROM $sTable2 a
GROUP BY a.songs_id
) bb ON bb.songs_id = b.songsID
LEFT JOIN (
SELECT AVG(rating) AS rating, COUNT(rating) AS ratings_count, c.songid
FROM $sTable3 c
GROUP BY c.songid
) bbb ON bbb.songid = b.songsID
LEFT JOIN (
SELECT c.songid, c.userid,
CASE WHEN EXISTS
(
SELECT songid
FROM $sTable3
WHERE songid = c.songid
) Then 'User Voted'
else
(
'Not Voted'
)
end
AS voted
FROM $sTable3 c
WHERE c.userid = $userid
GROUP BY c.songid
) bbbb ON bbbb.songid = b.songsID
EDIT: He aquí una descripción de lo que la consulta está haciendo: -
Tengo tres tablas:
$ estable = una mesa de canciones (songid, mp3link, artwork, useruploadid etc.)
$ = sTable2 una mesa de proyectos con canciones relacionadas con ellas (projectId, SongID, nombre del proyecto, etc.)
$ = sTable3 una tabla de calificaciones de canciones (SongID, ID de usuario, valoraciones)
Todos estos datos se envían a una matriz JSON y se muestran en una tabla en mi aplicación para proporcionar una lista de canciones, combinadas con los proyectos y los datos de clasificación.
la propia consulta realiza lo siguiente en este orden: -
- Recoge todas las filas de $ estable
- se une a $ sTable2 en songsID y cuenta el número de filas (proyectos) en esta tabla que tienen las mismas canciones ID
- Se une a $ stable3 en songsID y calcula un promedio de la columna 'clasificación' en esta tabla que tienen las mismas canciones ID
- En este punto, también cuenta el número total de filas en $ sTable3 que tienen el mismo ID de canción para proporcionar un número total de votos .
- Finalmente realiza una comprobación en todas estas filas para ver si el $ userid (que es una variable que contiene el ID del usuario conectado) coincide con las tiendas 'userid' en $ sTable3 para cada fila para verificar si un el usuario ya ha votado un ID de canción determinado o no. Si coincide, devuelve "Usuario votado" si no devuelve "No votado". Lo muestra como una columna separada en mi matriz JSON, que compruebo contra el lado del cliente en mi aplicación y agrego una clase a.
Si hay más detalles que alguien necesita, por favor házmelo saber. Gracias a todos.
EDIT:
Gracias a la excelente primer intento Aurimis' estoy acercando a una solución mucho más sencilla.
Este es el código que he intentado basándome en esa sugerencia.
SELECT SQL_CALC_FOUND_ROWS ".str_replace(" , ", " ", implode(", ", $aColumns))."
FROM
(SELECT
$sTable.songsID, COUNT(rating) AS ratings_count,
AVG(rating) AS ratings
FROM $sTable
LEFT JOIN $sTable2 ON $sTable.songsID = $sTable2.songs_id
LEFT JOIN $sTable3 ON $sTable.songsID = $sTable3.songid
GROUP BY $sTable.songsID) AS A
LEFT JOIN $sTable3 AS B ON A.songsID = B.songid AND B.userid = $userid
Sin embargo, hay varios problemas. Tuve que quitar la primera línea de su respuesta ya que causó un error 500 de servidor interno:
IF(B.userid = NULL, "Not voted", "User Voted") AS voted
Obviamente ahora el 'cheque votaron' funcionalidad se pierde.
Además, y lo que es más importante, no devuelve todas las columnas definidas en mi matriz, solo la ID de canción. My JSON devuelve la columna Desconocida 'song_name' en 'field list' - Si la elimino de mi matriz $ aColumns, pasará a la siguiente.
Estoy definiendo mis columnas al comienzo de mi secuencia de comandos, ya que esta matriz se usa para filtrar y armar la salida para la codificación JSON. Esta es la definición de $ aColumns: -.
$aColumns = array('songsID', 'song_name', 'artist_band_name', 'author', 'song_artwork', 'song_file', 'genre', 'song_description', 'uploaded_time', 'emotion', 'tempo', 'user', 'happiness', 'instruments', 'similar_artists', 'play_count', 'projects_count', 'rating', 'ratings_count', 'voted');
Con el fin de probar rápidamente el resto de la consulta modifiqué la primera línea dentro de la sub consulta para seleccionar $ Estable * en lugar de $ sTable.songsID (recordemos $ estables es la tabla de canciones)
Entonces ... La consulta obviamente funcionó, pero con un rendimiento terrible, por supuesto. Pero solo devolvió 24 canciones del conjunto de datos de prueba de 5000 canciones. Por lo tanto, cambié tu primer 'JOIN' a 'LEFT JOIN' para que se devolvieran las 5000 canciones. Para aclarar la consulta, es necesario devolver TODAS las filas en la tabla de canciones, pero con varios bits adicionales de datos de los proyectos y tablas de calificaciones para cada canción.
Así que ... Estamos llegando y estoy seguro de que este es un enfoque mucho mejor, solo necesita algunas modificaciones. Gracias por tu ayuda hasta ahora Aurimis.
parece ser que la persona que escribió la consulta no era nuevo para MySQL – newtover
lo escribí yo mismo por 'googlear', varias preguntas aquí, y leyendo mucho. Sin embargo, en esencia, he unido varias piezas en una consulta de "trabajo" para lograr lo que quiero. Aunque entiendo qué hace cada parte de la consulta y por qué funciona, no tengo la experiencia para saber si estoy haciendo esto de manera eficiente o no. Mi instinto de mi experiencia con otros idiomas me dice que no lo soy. Por lo tanto, agradecería el consejo de los desarrolladores de MySQL más experimentados. :) – gordyr
¿Puedes describir cuál debería ser el resultado esperado? – Peter