2017-01-05 14 views
3

У меня есть MySQL таблицы, как это, и я хотел бы вычислить TOP10 для каждого жанра:MySQL сумма рейтинга, группа по жанру, ограничение 10

  • rankings_2016 (TrackID, genreId, рейтинг, метка времени)
  • жанры (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 

Единственное решение, которое я нашел становится все в таблице, а затем 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 

благодарственное все заранее для ваших подсказок.


UPDATE

Логика в целом (и принят ответ) требует хороших индексов и производительную сервера.

ARTISTS в моем случае не удалось с ошибкой 500, если я не увеличил процессор. В общем случае замена LEFT на INNER экономит 1 секунду.

+0

Если производительность является проблемой и ранжирование не изменяется часто, рассмотрите предварительный расчет ответа. – alttag

+0

Рейтинги ежедневно меняются: мои фактические запросы предварительно заполняют некоторые таблицы, при этом все результаты тратят сотни тысяч строк в день. Как я могу ограничить до 20 непосредственно на стадии предварительного заполнения? – fab

+0

Убедитесь, что у вас есть указатель на таблице «timestamp». Не могу придумать ничего, что могло бы замедлить эти простые запросы. – Barmar

ответ

0

Рассмотрим коррелированный подзапрос счетчика, чтобы ранжировать ранжирование по группам Artist/Track/Genre. Затем используйте этот ранг вычисляемого столбец в внешнем запросе для фильтрации топа-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 
+0

Спасибо за поддержку. Я думаю, что во втором запросе u означал // «WHERE» subr.genreId = r.genreId // вместо «AND» // Тем не менее, я не смог выполнить оба из-за того, что они тайм-аут с ошибкой 500. Я смог вместо этого собрать пакет для TRACKS, который я включил в EDIT, который хорошо работает в 3 ", но если я LEFT JOIN artist_tracks, это также не так. – fab

+0

Что дает ваша консоль/workbench MySQL? веб-ошибка. Возможно, у вас довольно много данных и времени на веб-странице. И ваше обновление - это еще один вариант в MySQL с использованием @variables. Другие RDMS используют функцию окна «ROW_NUMBER». Этот коррелированный подзапрос будет работать в любом SQL-совместимом база данных. – Parfait