Как я могу упростить / улучшить производительность этого MySQL-запроса?

Я новичок в MySQL, и благодаря большой поддержке со стороны вас, более опытные ребята, мне удается справиться с трудностями, при этом я многому научился.

У меня есть запрос, который делает именно то, что я хочу. Однако мне это кажется очень запутанным, и я уверен, что должен быть способ упростить его.

Как можно улучшить и оптимизировать этот запрос для повышения производительности?

Большое спасибо

            $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

РЕДАКТИРОВАТЬ: Вот описание того, что делает запрос: -

У меня есть три таблицы:

  • $ sTable = таблица песен (songid, mp3link, artwork, useruploadid и т. д.)

  • $ sTable2 = таблица проектов со связанными с ними песнями (projectid, songid, название проекта и т. д.)

  • $ sTable3 = таблица рейтингов песен (songid, userid, rating)

Все эти данные выводятся в массив JSON и отображаются в таблице в моем приложении, чтобы предоставить список песен в сочетании с проектами и рейтинговые данные.

Сам запрос выполняет следующие действия в следующем порядке: -

  1. Собирает все строки из $ sTable
  2. Присоединяется к $ sTable2 по songID и подсчитывает количество строк (проектов) в этой таблице, которые имеют одинаковый songID
  3. Присоединяется к $ stable3 для songID и вычисляет среднее значение столбца 'rating' в этой таблице, имеющего тот же songID
  4. . На этом этапе также подсчитывается общее количество строк в $ sTable3, которые имеют одинаковый songID для предоставить общее количество голосов.
  5. Наконец, он выполняет проверку всех этих строк, чтобы увидеть, совпадает ли $ userid (которая является переменной, содержащей идентификатор пользователя, вошедшего в систему) с хранилищами 'userid' в $ sTable3 для каждой строки, чтобы проверить, соответствует ли пользователь уже проголосовал за данный songID или нет. Если он совпадает, возвращается «Проголосовал пользователь», если нет - «Не проголосовал». Он выводит это как отдельный столбец в мой массив JSON, который я затем проверяю на стороне клиента в моем приложении и добавляю класс.

Если кому-то нужны какие-то подробности, пожалуйста, дайте мне знать. Спасибо всем.

РЕДАКТИРОВАТЬ:

Благодаря отличной первой попытке Ауримиса я приближаюсь к гораздо более простому решению.

Это код, который я пробовал на основе этого предложения.

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

Однако есть несколько проблем. Мне пришлось удалить первую строку вашего ответа, так как это вызвало внутреннюю ошибку сервера 500:

IF(B.userid = NULL, "Not voted", "User Voted") AS voted 

Очевидно, теперь функция «проверки с голосованием» потеряна.

Кроме того, что более важно, он возвращает не все столбцы, определенные в моем массиве, а только songID.Мой JSON возвращает неизвестный столбец «song_name» в «списке полей» - если я удалю его из своего массива $ aColumns, он, конечно, перейдет к следующему.

Я определяю свои столбцы в начале моего скрипта, поскольку этот массив используется для фильтрации и объединения выходных данных для кодирования JSON. Это определение $ 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');

Чтобы быстро проверить остальную часть запроса, я изменил первую строку в подзапросе, выбрав $ sTable. *, А не $ sTable.songsID (помните, что $ sTable - это таблица песен )

Тогда ... Запрос явно работал, но, конечно, с ужасной производительностью. Но вернули только 24 песни из 5000 тестовых данных. Поэтому я изменил ваше первое «JOIN» на «LEFT JOIN», так что все 5000 песен были возвращены. Чтобы прояснить запрос, необходимо вернуть ВСЕ строки в таблице песен, но с различными дополнительными битами данных из проектов и таблиц рейтингов для каждой песни.

Итак ... Мы приближаемся, и я уверен, что это намного лучший подход, он просто требует некоторой модификации. Спасибо за вашу помощь, Ауримис.

7
задан newtover 12 December 2011 в 11:47
поделиться