【问题标题】:Calculating average rating on a post计算帖子的平均评分
【发布时间】:2018-08-22 14:03:45
【问题描述】:

我有以下实体:

post_id | post_title | post_body
-------------------------------------
1       | First post | Hello, world!

并想在帖子上注册评分,如下所示:

rating_id | rating_user_id | rating_post_id | rating_rating
1         | 23             | 1              | 3.5

我主要关心/问题是,我应该如何检索帖子的平均评分。我知道我可以使用这样的 SQL 查询来做到这一点:

SELECT AVG(rating_rating) FROM post_ratings WHERE rating_post_id = 2;

但是我每次都必须调用这个查询$post->getAverageRating() - 这是一个很大的性能问题吗? (请记住,每个帖子可能有数千个评分)

另一种方法是将平均评分存储在posts 表的新列中,并让 cron 作业计算平均值或其他什么?

最好的方法是什么?

【问题讨论】:

  • 这真的取决于用例的细节.. 数据库调用很昂贵,所以你想尽量减少它。一种方法是保留一个应用程序缓存,该缓存每 X 分钟进入数据库并加载新数据(或从头开始的所有数据)并在内存中计算,或加载已经计算的平均值,但是,您每 X 分钟执行一次而不是在每个帖子请求上。
  • 我在一个评论网站上工作,我们有一个每天运行 4 次的 cron,它按照你的建议运行,唯一的区别是最终评级是用 php 计算的
  • 没有。它不是。当它成为一个大的性能问题时,会发生两件事之一。要么你足够有钱,可以花钱请人来解决你的性能问题,要么你太有钱了。
  • 我认为每次运行它都不是问题,除非它是一个具有高负载和访问权限的大型站点。如果是这种情况,只需每小时或每 6 小时运行一次 cron 作业并创建/更新缓存。

标签: php mysql sql


【解决方案1】:

这是效率问题

如果这些评分会累积很多,最好保存计算出的平均值 我会在帖子表中添加 2 列,average_rating,total_ratings

ALTER TABLE posts ADD COLUMN average_rating DECIMAL (9,2);
ALTER TABLE posts ADD COLUMN total_ratings UNSIGNED (9) DEFAULT 0;

并在添加新评级时填充它们,因此您不需要 cron 作业 注意计算平均值的查询顺序

MySQL + PHP 代码应该是这样的:

    $query = "UPDATE posts SET total_ratings  = total_ratings + " . $rating_rating . " WHERE post_id = " . $post_id;
    $db->query($query);
    $query = "UPDATE posts SET average_rating = average_rating * (total_ratings -1 / total_ratings) + " . $rating_rating ." / total_ratings WHERE post_id = " . $post_id;
$db->query($query);

这样您可以立即更新帖子表,而无需任何 cron 作业

【讨论】:

    【解决方案2】:

    至于比较性能-这取决于

    1. 评级是静态的。如果您希望现有帖子有新的评级,我还是会即时计算它们。
    2. 相对于总体帖子,您需要对多少帖子进行评分。如果您有数百万个帖子,并且只需要几千个帖子的平均评分,那么单独执行它们也是有意义的。

    【讨论】:

      【解决方案3】:

      数据库调用非常昂贵,尤其是当您每次都必须进行平均时。

      与您当前的解决方案相比,您有以下更优化的选项。

      1. 当按照@Guy L 提到的那样进行评分时,有一个列来计算和存储帖子的平均评分

      2. 使用 TTL(生存时间)实现缓存

      示例:

      public function getAverageRating() {
           $post_id = 'post' . $this->id;
           if(Cache::has($post_id))
               return Cache::get($post_id);
           $rating = //fetch rating from DB
           Cache::set($post_id, $rating, 120); //ratings will be in the cahce for 120secs
           return $rating
      }
      

      希望对你有帮助。

      【讨论】:

        猜你喜欢
        • 2013-07-31
        • 1970-01-01
        • 1970-01-01
        • 2018-01-04
        • 2017-12-03
        • 2015-01-30
        • 2015-08-27
        • 2017-10-11
        • 1970-01-01
        相关资源
        最近更新 更多