MySQL总和排名,按类型分组,限制10

时间:2017-01-05 22:43:11

标签: mysql group-by limit database-performance

我有这样的MySQL表格,我想计算每种类型的TOP10:

  • rankings_2016(trackId,genreId,ranking,timestamp)
  • 流派(genreId,genreName)
  • 曲目(trackId,trackName,genreId)
  • 艺术家(artistId,artistName)
  • artists_tracks(artistId,trackId)

我想为每个类型,每个曲目和每个艺术家获得TOP10排名。

曲目或艺术家最多可以有2种流派。排名可能相同。只是为了得到LIMIT 2的想法:

  genreId | trackId | ranking
 ---------------------------------
   0         1111      100
   0         2222       99
   1         1111      100
   1         2222       99

  genreId | artistId | ranking
 ---------------------------------
   0         1111      100
   0         2222       99
   1         1111      100
   1         2222       99

我发现的唯一解决方案是将所有内容都放在一个表格中,然后在页面中限制为10,但是它在大小方面会杀死我的数据库(我的资源有限)。

对于我写过的曲目:

SELECT trackId, genreId, @newRank := SUM(ranking) as ranking
FROM rankings_2016
WHERE timestamp >= ( select unix_timestamp('2016-01-01') )
AND timestamp <= ( select unix_timestamp('2016-12-31') )
GROUP BY trackId, genreId

对于艺术家:

SELECT artistId, genreId, @newRank := SUM(a1.ranking) as ranking
FROM rankings_2016 a1
LEFT JOIN artists_tracks a2
ON a1.trackId = a2.trackId
WHERE timestamp >= ( select unix_timestamp('2016-01-01') )
AND timestamp <= ( select unix_timestamp('2016-12-31') )
GROUP BY artistId, genreId

提前感谢所有提示。

<小时/>

更新

一般逻辑(和接受的回复)需要良好的索引和高性能服务器。

我的案例中的艺术家因错误500而失败,除非我增加了CPU。 一般情况下,用INNER替换LEFT会节省1秒钟。

1 个答案:

答案 0 :(得分:0)

考虑相关计数子查询,按艺术家/曲目/流派分组对排名进行排名。然后在外部查询中使用此 rank 计算列来过滤每个分组的前10个:

艺术家排名 (每位艺术家和流派排名前10位)

SELECT main.artistId, main.genreId, main.ranking
FROM
 (
   SELECT a.artistId, r.genreId, r.ranking,
          (SELECT COUNT(*) FROM rankings_2016 subr
           LEFT JOIN artists_tracks suba ON subr.trackId = suba.trackId
           WHERE suba.artistId = a.artistId
           AND subr.genreId = r.genreId
           AND subr.ranking >= r.ranking) AS rn
   FROM rankings_2016 r
   LEFT JOIN artists_tracks a ON r.trackId = a.trackId
   WHERE r.timestamp BETWEEN ( select unix_timestamp('2016-01-01') )
                         AND ( select unix_timestamp('2016-12-31') ) 
 ) AS main

WHERE main.rn <= 10

跟踪排名 (每首曲目和流派排名前10位)

SELECT main.trackId, main.genreId, main.ranking
FROM
 (
   SELECT r.trackId, r.genreId, r.ranking,
          (SELECT COUNT(*) FROM rankings_2016 subr               
           WHERE subr.genreId = r.genreId
           AND subr.trackId = r.trackId
           AND subr.ranking >= r.ranking) AS rn
   FROM rankings_2016 r
   WHERE r.timestamp BETWEEN ( select unix_timestamp('2016-01-01') )
                         AND ( select unix_timestamp('2016-12-31') ) 
 ) AS main

WHERE main.rn <= 10