数据库devise:计算账户余额
我如何devise数据库来计算帐户余额?
1)目前我从交易表中计算账户余额在我的交易表中我有“描述”和“金额”等。
然后,我将所有的“金额”值加起来,这将计算出用户的账户余额。
我向我的朋友展示了这一点,他说这不是一个好的解决scheme,当我的数据库增长将减慢? 他说我应该创build单独的表来存储计算的账户余额。 如果这样做,我将不得不保持两张表,而且它的风险很大,账户余额表可能不同步。
任何build议?
编辑 :选项2:我应该添加一个额外的列到我的交易表“余额”。 现在我不需要经过许多行数据来执行我的计算。
约翰买了100美元的贷款,他偿还了60美元,然后又增加了200美元。
金额$ 100,余额$ 100。
金额 – $ 60,余额$ 40。
金额$ 200,余额$ 240。
一个从未被优雅地解决的古老的问题。
我所使用的所有银行服务包都将余额存入账户实体。 从运动历史中计算它是不可想象的。
正确的方法是:
- 移动表为每个账户都有一个“期初余额”交易。 当您需要将旧运动从活动运动表移动到历史logging表时,您需要在几年的时间内完成此操作。
- 账户实体有一个余额字段
- 移动表上有一个触发器,用于更新贷记和借记账户的账户余额。 显然,它有承诺控制。 如果你不能触发,那么需要有一个独特的模块,在承诺控制下写入动作
- 你有一个“安全网”程序,你可以离线运行,重新计算所有的余额,并显示(并可选地更正)错误的余额。 这对testing非常有用。
一些系统将所有的运动存储为正数,并通过反转起始/结束字段或用标志表示信用/借记。 就个人而言,我更喜欢信用领域,借记领域和签署的数额,这使得逆转更容易遵循。
请注意,这些方法适用于现金和证券。
证券交易可能会非常棘手,尤其是对于公司行为,您将需要适应一次交易,即更新一个或多个买家和卖家的现金余额,他们的证券头寸余额以及可能的经纪人/存款人。
您应该存储当前帐户余额并随时保持最新状态。 交易表只是过去发生的事情的logging,不应该为了获取当前的余额而高频率地使用。 考虑到许多查询不只是想要余额,他们想要过滤,sorting和他们分组等等。总结在复杂的查询中创build的每个事务的性能损失将削弱甚至一个适中大小的数据库。
对这对表的所有更新都应在交易中进行,并应确保所有内容都保持同步(并且帐户永远不会超过限额)或者事务回滚。 作为额外的措施,您可以运行审计查询来定期检查这个问题。
这个问题的一个常见的解决scheme是在快照模式中保持一个(比方说)每个月的期初余额。 计算当前余额可以通过将月份的交易数据添加到月度期初余额中来完成。 这种方法通常在账户包中使用,尤其是在可能进行货币转换和重估的情况下。
如果数据量有问题,您可以将旧款余额归档。
另外,如果系统上没有专用的外部数据仓库或pipe理报告function,则余额对于报告非常有用。
当然,你需要在每行存储你的当前余额,否则它太慢了。 为了简化开发,您可以使用约束,这样就不需要触发器和数据完整性的定期检查。 我在这里描述非规范化来执行业务规则:运行汇总
你的朋友是错的,你是对的,我build议你现在不要改变。
如果你的分贝因为这个变慢了,并且在你核实了所有剩下的部分(适当的索引)之后,可能会使用一些非规范化。
然后,您可以在Accounts表中添加BalanceAtStartOfYear字段,并仅汇总今年的logging(或任何类似的方法)。
但是我肯定不会推荐这种方法。
这里是想build议你如何以非常简单的方式储存你的期初余额:
-
在事务表上创build一个触发器函数,仅在更新或插入后调用。
-
在帐户的主表中创build名称为“打开余额”的列。
-
将您的期初余额保存在主表中的期初余额列中。
-
你甚至不需要使用服务器端语言使用这个存储arrays,只需要使用像PostgreSQL中可用的数据库数组函数即可。
-
当你想重新计算你在数组中打开的余额时,只需将你的事务表与数组函数分组,并更新主表中的所有数据。
我已经在PostgreSQL中做到了这一点,工作正常。
在您的交易表格变得繁重的一段时间内,您可以根据date划分您的交易表格,以加速performance。 这种方法非常简单,不需要使用任何额外的表,如果连接表会降低性能,因为join的小表会给你高性能。
这是一个数据库devise,我只有一个表,用于存储操作/事务的历史logging。 目前在许多小型项目上工作很有魅力。
这并不取代具体的devise。 这是一个通用的解决scheme,可以适应大多数的应用程序。
id :int标准行ID
operation_type :int操作types。 支付,收取,利息等
source_type :操作继续的int。 目标表或类别:用户,银行,供应商等
source_id :数据库中源的ID
target_type :int对应用的操作。 目标表或类别:用户,银行,供应商等
target_id :数据库中目标的int id
金额 :小数(19,2签名)价格价值正面或负面的总和
account_balance :十进制(19,2 signed)产生的余额
extra_value_a :decimal(19,2 signed)[这是不使用string存储的最通用的选项],您可以存储额外的数字:利息百分比,折扣,减less等。
created_at :时间戳
对于source_type和target_type,最好使用枚举或表appart。
如果你想要一个特定的平衡,你可以查询最后一个按照created_at降序排列的操作。你可以通过source,target,operation_type等进行查询。
为了获得更好的性能,build议将当前余额存储在所需的目标对象中。
简单的答案:三个都做。
存储当前余额; 并在每个交易中存储当前余额的移动和快照。 这将在任何审计中给予额外的协调。
我从来没有在核心银行系统上工作过,但是我曾经在投资pipe理系统上工作,根据我的经验,这是如何完成的。