数据库存储计算值是否为不良实践?电商点赞场景咨询
要不要把点赞数存在Product表中?这是个权衡问题,而非绝对的“坏主意”
这其实是开发中非常常见的读性能 vs 数据一致性的抉择,没有一刀切的答案,得结合你的电商场景来判断:
直接存储点赞数的优势
- 大幅提升读性能:如果你的产品页面访问量高(比如热门商品每秒几十上百次请求),每次请求都去
ProductLike表做COUNT(*)关联查询,会给数据库带来不小的压力——尤其是当ProductLike表数据量达到百万、千万级时,count操作的耗时会明显上升,拖慢页面响应。直接存在Product表的字段里(比如like_count),读请求只需要单表查询,效率高很多。 - 实现更简单:前端和后端接口都不用处理复杂的关联逻辑,直接取字段返回就行,减少代码复杂度。
潜在的问题和风险
- 数据一致性风险:每次用户点赞/取消点赞,你需要同时操作两张表:在
ProductLike里新增/删除记录,还要更新Product的like_count。这就必须依赖事务保证原子性,如果中间任何一步失败(比如服务崩溃、网络波动),就会出现两边数据不一致的情况——比如计数加了,但实际没有对应的点赞记录,或者反过来。 - 并发更新冲突:如果多个用户同时给同一个产品点赞,可能会出现“更新丢失”的问题。比如两个请求同时读到
like_count=10,各自加1后写回11,但实际应该是12。解决这个问题需要引入乐观锁(比如给Product加version字段)或者用原子更新语句(UPDATE Product SET like_count = like_count + 1 WHERE id = ?),这会增加代码的复杂度。
怎么判断该选哪种方式?
适合存储点赞数的场景
- 产品页面访问量远高于点赞操作频率:比如电商的爆款商品,每天几十万次页面浏览,但点赞只有几千次,这时候读性能的优先级远高于一致性的复杂度。
- 可以接受短暂的数据不一致:比如允许点赞数和实际记录有几分钟的误差,后面通过定时任务修正,这种场景下存储计数完全没问题。
更适合实时计算的场景
- 点赞操作非常频繁,且对一致性要求极高:比如需要精确统计每个用户的点赞记录,不能有任何误差,或者产品是核心的UGC内容,点赞数必须绝对准确。
- 产品访问量很低:比如小众商品,每天只有几十次访问,
COUNT(*)的性能影响可以忽略,这时候实时计算更省心,不用处理一致性问题。
折中方案推荐
如果想兼顾性能和一致性,可以试试这些方法:
- 用缓存做中间层:把点赞数存在Redis里,用户点赞时先更新Redis的计数,再异步去更新
ProductLike和Product表。读请求直接从Redis取,性能拉满,异步任务还能保证最终一致性。 - 定时同步计数:每隔一段时间(比如5分钟)跑个定时任务,统计
ProductLike表中每个产品的点赞数,更新到Product的like_count字段。平时读请求直接取字段,定时修正数据,适合对实时性要求不高的场景。 - 原子更新语句:如果要实时更新,直接用
UPDATE Product SET like_count = like_count + 1 WHERE id = ?这种原子操作,数据库会保证这个更新是线程安全的,避免并发冲突。
总的来说,把计算值存在数据库里不是坏主意,关键是看你的业务优先级——是更看重页面响应速度,还是绝对的数据准确性。根据自己的场景选最合适的方案就好。
内容的提问来源于stack exchange,提问作者Arad
相关产品推荐
相关产品推荐

