我有以下实体:
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作业计算平均值?
解决此问题的最佳方法是什么?
答案 0 :(得分:1)
关于性能比较-取决于
答案 1 :(得分:1)
这是效率问题
如果这些额定值和哪些额定值会大量叠加,则最好保存计算出的平均值 我会在posts表中添加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);
这样,您可以立即更新posts表,而无需执行任何cron作业
答案 2 :(得分:1)
数据库调用非常昂贵,尤其是当您每次必须求平均值时。
与当前解决方案相比,您具有以下最佳选择。
具有一列,用于计算和存储帖子的平均评分,如@Guy L所述。
使用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
}
希望有帮助。