将统计数据存储在数据库中或在运行时计算它们?

时间:2013-10-26 12:59:51

标签: mysql sql

我有一个应用程序,用户的活动将获得积分奖励。 将有一个点图表,为某些行动分配一定数量的点。

我的问题是哪种方法更好,最重要的是为什么?

方法1 : - 在mysql中创建一个userPoints表,并在每个用户操作中插入点。当用户转到他们的个人资料时,查询数据库中的点数并显示它们。

例如:
用户购买物品
查询数据库:在userPoints中为用户2插入5个点 用户跟随一个地方
查询数据库:在userPoints中为用户2插入7个点 用户出售他们的项目
查询数据库在userPoints中为用户2插入-5个点

方法2 : - 不要将点存储在表中,而是计算用户已完成的操作数(从数据库中获取计数和类型),然后在运行时将所有类型的操作乘以一定数量的点,只要数量为积分是必需的(例如,当他们访问他们的个人资料时)

例如
用户访问他们的个人资料以查看他们有多少积分 查询数据库并统计所拥有的物品,地点跟随,友谊然后乘以物品数x5,以下数量x7和友谊数x10并显示数字

为Steven编辑:

让我直截了当地说,这是我应该采取的行动的年代表吗?如何收紧并减少查询次数?

  • 购买商品的actionId为1,奖励积分为5(这在数据库的 - actions表中指定)
  • Kylie(用户ID:1)购买商品。
  • 查询数据库:将项目添加到用户ID1
  • 的userItems表中
  • 查询数据库:在userActions表中注册一个操作 - userId:1,actionId:1
  • 查询DB SET userPointsTotal = userPointsTotal +积分奖励(在这样的一个中嵌套两个查询:set userPointsTotal = userPointsTotal +(从actuionid = 1的操作中选择点))
  • 查询数据库获取userPointsTotal并在Kylie的个人资料中显示值
  • 将来,请参阅表userActions,以便用户可以获取状态标题,具体取决于某些活动类型(社会地位或所有权状态)

3 个答案:

答案 0 :(得分:1)

我推荐一种混合方法。如果你在表格中严格存储点数,那么很容易忘记谁有什么原因。或者,如果您的用户群增长,不断重新计算它们会立即关闭您的服务器。如果您改为,每5分钟,1小时,12小时或任何间隔重新计算点数,并将结果存储在userPoints表中,您可以拥有快速访问速度,因为您只是查找表格。此外,如果您碰巧错误计算积分或陷入用于计算积分的逻辑中,您可以轻松修复代码并重新计算。

答案 1 :(得分:1)

由于点数可以被认为是基于各个动作的聚合函数,因此问题归结为何时使用预聚合的决定。

这两种方法在不同情况下都有效:

  • 当计算聚合需要很少的工作,或者不经常计算聚合时,使用预聚合会增加复杂性,甚至可能会降低性能,因此最好存储“原始事件”。
  • 当计算聚合需要经历大量数据时,或者经常请求聚合时,预聚合成为提高性能的有效方法。

请注意,数据库可以帮助您进行预聚合:如果您在操作表上定义索引,然后查询计数和总计而不是单个操作(即按照您在问题的方法2中建议的方式进行操作)然后,DB将使用索引中的数据来获取计数而不实际进行计数。这为您提供了与第一种方法类似的性能,RDBMS为您完成了大部分工作。

答案 2 :(得分:1)

你想要存储:

  1. 操作 - 列出操作和为每个操作定义的点的表。这将作为您的域表。

  2. 用户操作 - 一个复合键表(user_id,action_id),列出用户已完成的操作及其获得的积分(如果是以下情况,您可以将其存储在此处用户完成后,操作的点值会发生变化。您可以随时执行SUM(user_actions.points)以获得用户获得的精确点数。

  3. 用户总数 - 枚举用户获得的积分总和的值。您可以在记录用户操作时更新的Users表上创建一个列,或者这可以是存储在用户索引或缓存中的user_actions.points的总和,它定期更新(例如Solr,Memcached)。这将允许您显示大量的聚合数字,而不会在每次显示用户列表时使用昂贵的聚合函数敲击数据库。

  4. 这为您提供了最好的世界。您可以快速了解用户获得多少积分,如果他们“迷路”则重新计算总计的可靠方法,以及参考完整性/附加信息的域表。