【问题标题】:MySQL sum ranking, group by genre, limit 10MySQL总和排名,按流派分组,限制10
【发布时间】:2017-01-05 22:43:11
【问题描述】:

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

  • rankings_2016(trackId、genreId、排名、时间戳)
  • 流派(流派 ID、流派名称)
  • 曲目(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

我找到的唯一解决方案是将所有内容都放在一个表中,然后在页面中设置 LIMIT 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

提前感谢大家的提示。


更新

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

除非我增加 CPU,否则我的 ARTISTS 会因错误 500 而失败。 一般来说,用 INNER 替换 LEFT 可以节省 1 秒。

【问题讨论】:

  • 如果性能是一个问题并且排名不经常变化,请考虑预先计算答案。
  • 排名每天都在变化:我的实际查询预先填充了一些表,所有结果每天浪费数十万行。如何在预填充阶段直接限制为 20 个?
  • 确保您在timestamp 表上有一个索引。想不出还有什么可能会减慢这些简单查询的速度。
  • 性能还可以,大小是 KO:我想获得每个流派、每个曲目和每个艺术家的 TOP10 排名。谢谢
  • 也许这已经解决了,但如果你还在苦苦挣扎,请参阅meta.stackoverflow.com/questions/333952/…

标签: mysql group-by limit database-performance


【解决方案1】:

考虑一个相关计数子查询,以按艺术家/曲目/流派分组对排名进行排序。然后在外部查询中使用这个 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

【讨论】:

  • 感谢您的支持。我认为在第二个查询中,你的意思是//“WHERE”subr.genreId = r.genreId //而不是“AND”//但是我无法同时执行这两个操作,因为它们因错误 500 而超时。我能够打包一个用于我在 EDIT 中包含的 TRACKS,它在 3" 中表现良好,但如果我 LEFT JOIN Artists_tracks 它也会超时
  • 您的 MySQL 控制台/工作台提供什么? 500 是网络错误。可能您有相当多的数据和网页超时。您的更新是 MySQL 中使用 @variables 的另一个选项。其他 RDMS 使用ROW_NUMBER 窗口函数。此相关子查询适用于任何符合 SQL 的数据库。
猜你喜欢
  • 2021-01-06
  • 2020-02-29
  • 2011-02-08
  • 1970-01-01
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多