如何简化/改进此MySQL查询的性能?

gor*_*dyr 7 mysql query-optimization

我是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
Run Code Online (Sandbox Code Playgroud)

编辑:这是查询正在做什么的描述: -

我有三张桌子:

  • $ sTable =歌曲表(songid,mp3link,artwork,useruploadid等)

  • $ sTable2 =与其相关联的歌曲的项目表(项目,歌曲,项目名称等)

  • $ sTable3 =歌曲收视率表(songid,userid,rating)

所有这些数据都输出到JSON数组并显示在我的应用程序的表格中,以提供歌曲列表,结合项目和评级数据.

查询本身按此顺序执行以下操作: -

  1. 从$ sTable收集所有行
  2. 在songsID上连接到$ sTable2并计算此表中具有相同songsID的行数(项目)
  3. 在songsID上加入$ stable3并计算出此表中具有相同songsID的列'rating'的平均值
  4. 此时,它还计算$ sTable3中具有相同songID的总行数,以提供总投票数.
  5. 最后,它对所有这些行执行检查,以查看$ userid(包含登录用户ID的变量)是否与$ sTable3中每行的'userid'存储匹配,以便检查用户是否已经是否对某个歌曲进行了投票.如果它匹配则返回"User Voted",否则返回"Not Voted".它将它作为一个单独的列输出到我的JSON数组中,然后我在我的应用程序中检查客户端并添加一个类.

如果有任何需要的细节,请告诉我.谢谢大家.

编辑:

感谢Aurimis出色的首次尝试,我正在接近一个更简单的解决方案.

这是我根据该建议尝试的代码.

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
Run Code Online (Sandbox Code Playgroud)

但是有几个问题.我不得不删除你的答案的第一行,因为它导致500内部服务器错误:

IF(B.userid = NULL, "Not voted", "User Voted") AS voted 
Run Code Online (Sandbox Code Playgroud)

显然现在"投票检查"功能已丢失.

此外,更重要的是,它不会返回我的数组中定义的所有列,只返回songsID.我的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');
Run Code Online (Sandbox Code Playgroud)

为了快速测试查询的其余部分,我修改了子查询中的第一行,选择$ sTable.*而不是$ sTable.songsID(记住$ sTable是歌曲表)

然后......查询显然有效,但当然表现糟糕.但只返回了5000首歌曲测试数据集中的24首歌曲.因此,我将您的第一个'JOIN'更改为'LEFT JOIN',以便返回所有5000首歌曲.为了澄清查询需要返回歌曲表中的所有行,但是每个歌曲的项目和评级表中都有各种额外的数据.

所以...我们到了那里,我确信这是一个更好的方法,只需要一些修改.感谢你对Aurimis的帮助.

new*_*ver 3

SELECT SQL_CALC_FOUND_ROWS
    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,
    IF(user_ratings_count, 'User Voted', 'Not Voted') as voted
FROM (
    SELECT
        sp.songsID, projects_count,
        AVG(rating) as rating,
        COUNT(rating) AS ratings_count,
        COUNT(IF(userid=$userid, 1, NULL)) as user_ratings_count
    FROM (
        SELECT songsID, COUNT(*) as projects_count
        FROM $sTable s
        LEFT JOIN $sTable2 p ON s.songsID = p.songs_id
        GROUP BY songsID) as sp
    LEFT JOIN $sTable3 r ON sp.songsID = r.songid
    GROUP BY sp.songsID) as spr
JOIN $sTable s USING (songsID);
Run Code Online (Sandbox Code Playgroud)

您将需要以下索引:

  • $sTable2 上的 (songs_id)
  • $sTable3 上的组合(歌曲 ID、评级、用户 ID)

查询背后的想法:

  • 子查询使用 INT 进行操作,以便子查询的结果可以轻松放入内存
  • 左连接单独分组以减少笛卡尔积
  • 用户投票与其他评级在同一子查询中进行计数,以避免昂贵的相关子查询
  • 所有其他信息均在最终连接中检索