使用ORDER时查询最高评级视频(喜欢/不喜欢)

时间:2014-01-22 22:43:39

标签: mysql sql performance sql-order-by

(使用MySQL)我有一个视频表(简化):

+---------+-------------+-------------+
| videoID |  videoName  | videoAuthor |
+---------+-------------+-------------+
|       1 | cool_video1 | rocky       |
|       2 | mixingTest2 | sensable    |
+---------+-------------+-------------+

和视频评分表,也就是说,每当用户喜欢或不喜欢视频时,都会在videoRatings表中添加/更新一行: 例如,这意味着带有videoID 1的视频有两个喜欢和一个不喜欢。 videoRatings表中的“1”是类似的。 “2”是不喜欢(简化)

+---------------+---------+-------------------+
| videoRatingID | videoID | videoRatingTypeID |
+---------------+---------+-------------------+
|           121 |       1 |                 1 |
|           234 |       1 |                 1 |
|           290 |       1 |                 2 |
+---------------+---------+-------------------+

现在,很简单,我想要做的就是获得大约100,000个视频的得分最高的视频 我自然会这样做:

SELECT Videos.videoID,
             COUNT(CASE WHEN videoRatingTypeID =1 THEN 1 ELSE NULL END) AS likes,
             COUNT(CASE WHEN videoRatingTypeID =2 THEN 1 ELSE NULL END) AS dislikes
      FROM Videos
      LEFT JOIN VideoRatings ON VideoRatings.videoID = Videos.videoID
      GROUP BY Videos.videoID
ORDER BY likes DESC

但是此查询大约运行半秒钟。这让我担心,当视频表达到> 1mil时,这将更长。 videoRatings表非常小(约40行),视频表约为100,000行。

我在Videos表中有视频ID的索引,在videoID,videoRatingID和videoID + videoRatingID上的复合索引的videoRatings表中有索引

我没有看到更好的方法来做到这一点。我已经阅读了几篇关于通过外部移动订单的帖子。但是当我这样做时:

SELECT * FROM (
SELECT Videos.videoID,
             COUNT(CASE WHEN videoRatingTypeID =1 THEN 1 ELSE NULL END) AS likes,
             COUNT(CASE WHEN videoRatingTypeID =2 THEN 1 ELSE NULL END) AS dislikes
      FROM Videos
      LEFT JOIN VideoRatings
      GROUP BY Videos.videoID
) tmp
ORDER BY tmp.likes DESC

没有改善。

有什么更好的方法来处理此布局或此查询?谢谢!

1 个答案:

答案 0 :(得分:1)

对于真正的可扩展性,我认为您需要一个维护摘要表的解决方案。与此同时,这可能会更快:

select v.videoID,
       (select count(*)
        from VideoRatings vr
        where vr.videoID = v.videoID and
              videoRatingTypeId = 1
       ) as likes,
       (select count(*)
        from VideoRatings vr
        where vr.videoID = v.videoID
              videoRatingTypeId = 2
       ) as dislikes
from Videos v;

请确保您在VideoRatings(videoId, videoRatingTypeId)上有一个索引(实际上,索引中的类型ID不是那么重要,但它可以提供帮助)。

这将取代整套视频和评分中的group by,包括索引扫描和小型聚合。只要videoRatings的索引适合内存,这就会向上扩展。

编辑:

您的视频评分表非常简洁,包含的信息远远少于喜欢和不喜欢的摘要数量。例如,这样的表可能具有评级的日期/时间和进行评级的人。

BUT。您正在通过insert行向此表添加新的评分。嗯,与update另一个表(可能是videos)的信息几乎相同。然后将您当前的表视为历史日志。

使用update的优点是可以在日志变大时截断日志。现在,您必须保留每个视频的开始时的每个评级。