Moh*_*mad 19 mysql database-design rating-system
在数据库中存储产品评级的最佳方法是什么?我记得以下两个(简化,并假设一个MySQL数据库)场景:
在products表中创建两列,分别存储所有投票的数量和总和.使用列可以在运行时或使用查询获得平均值.
这种方法意味着我只需要访问一个表,简化了一些事情.
通过创建另一个表来存储评级来规范化数据.
这会将评级数据隔离到一个单独的表中,而产品表则提供有关可用产品的数据.虽然它需要加入或单独查询评级.
哪种方法最好,规范化或非规范化?
Ale*_*lec 33
强烈建议使用不同的评级表来保持动态.不要担心数百(或数千或数万)的条目,这些都是数据库的花生.
建议:
表产品
- id
- 名称
- 等
table products_ratings
- id
- productId
- rating
- date(如果需要)
- ip(如果需要,例如防止双重评级)
- 等
检索产品的所有评级1234:
SELECT pr.rating
FROM products_ratings pr
INNER JOIN products p
ON pr.productId = p.id
AND p.id = 1234Run Code Online (Sandbox Code Playgroud)
产品的平均评级1234:
SELECT AVG(pr.rating) AS rating_average -- or ROUND(AVG(pr.rating))
FROM products_ratings pr
INNER JOIN products p
ON pr.productId = p.id
AND p.id = 1234";Run Code Online (Sandbox Code Playgroud)
获得产品列表及其平均评分同样容易:
SELECT
p.id, p.name, p.etc,
AVG(pr.rating) AS rating_average
FROM products p
INNER JOIN products_ratings pr
ON pr.productId = p.id
WHERE p.id > 10 AND p.id < 20 -- or whateverRun Code Online (Sandbox Code Playgroud)
我知道我的答案并不是您真正要求的,但您可能希望有机会促进您的系统的新产品几乎永远无法击败旧产品。假设您将获得评分为 99% 的产品。如果按照评分最高的产品来排序,新产品很难获得高分。
除非您绝对需要,否则不要存储每个评级的记录。这种情况的一个例子是心理实验,该实验倾向于分析评估者本身的特定属性。嗯是的!您必须同样疯狂才能将每个费率存储在单独的记录中。
现在,来到解决方案,在您的产品表中再添加两列:AverageRating和RateCount。你会在其中存储什么?好吧,假设您已经计算出两个数字的平均值:2和3,即2.5;如果新的速率为10,则将平均值 ( 2.5 ) 乘以速率计数(在本例中为2)。现在,你有5 个。将此结果添加到新的速率值 ( 10 ) 并将结果除以3。
让我们用一个简单的公式来涵盖以上所有内容,
(AverageRating * RateCount + NewRateValue) / (RateCount + 1)
Run Code Online (Sandbox Code Playgroud)
所以(2.5 * 2 + 10) / (2 + 1) = 5。
在服务器端(而不是在数据库中)计算平均值,并将平均值存储在列中AverageRating,并将比率计数存储在RateCount列中。
很简单吧?!
只要不涉及审查、编辑或删除操作,该解决方案就不需要单独存储每个评级。然而,对于这种情况;假设您有一条评分为3的评论,所有者用户希望将其修改为4。那么,重新计算平均评分的公式将是这样的,
(AverageRating * RateCount - OldRateValue + NewRateValue) / RateCount
Run Code Online (Sandbox Code Playgroud)
https://math.stackexchange.com/a/106314