我是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, 歌曲,项目名称等。)
$ sTable3 =歌曲评分表(songid,userid,rating)
所有这些数据都输出到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
但是有几个问题。我不得不删除你的答案的第一行,因为它导致500内部服务器错误:
IF(B.userid = NULL, "Not voted", "User Voted") AS voted
显然现在“投票检查”功能已经丢失。
此外,更重要的是,它不会返回我的数组中定义的所有列,只返回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');
为了快速测试查询的其余部分,我修改了子查询中的第一行,选择$ sTable。*而不是$ sTable.songsID(记住$ sTable是歌曲表)
然后......查询显然有效,但当然表现糟糕。但只返回了5000首歌曲测试数据集中的24首歌曲。因此,我将您的第一个'JOIN'更改为'LEFT JOIN',以便返回所有5000首歌曲。澄清查询需要返回歌曲表中的所有行,但是每首歌曲的项目和评级表中都有各种额外的数据。
所以......我们到了那里,我确信这是一个更好的方法,只需要一些修改。感谢你对Aurimis的帮助。
答案 0 :(得分: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);
您需要以下索引:
查询背后的想法:
答案 1 :(得分:1)
让我尝试根据您的描述,而不是查询。我只会使用Songs
表示Table1
,Projects
表示Table2
,Ratings
表示Table3
- 为了清晰起见。
SELECT
/* [column list again] */,
IF(B.userid = NULL, "Not voted", "Voted") as voted
FROM
(SELECT
Songs.SongID, count(rating) as total_votes,
avg(rating) as average_rating /*[,.. other columns as you need them] */
FROM Songs
JOIN Projects ON Songs.SongID = Projects.SongID
LEFT JOIN Ratings ON Songs.SongID = Ratings.SongID
GROUP BY Songs.SongID) as A
LEFT JOIN Ratings as B ON A.SongID = B.SongID AND B.userid = ? /* your user id */
如您所见,您可以在一个相对简单的查询中获取有关歌曲的所有信息(仅使用Group by和count()/ avg()函数)。要获取特定用户是否对某首歌进行评级的信息,需要一个子查询 - 您可以在其中进行LEFT JOIN,如果用户标识为空 - 您知道他没有投票。
现在,我没有仔细检查你的查询,因为它看起来很复杂。可能是我错过了一些东西 - 如果是这种情况,请更新说明,我可以再试一次:)