我有一个名为transactions
的表,有大约2000万条记录。这个表每秒都在增长。
我用以下方式计算用户当前余额:
SELECT sum(`amount`) FROM `transactions` WHERE `user_id` = 1000;
我在我的网络应用程序的顶部栏中显示用户当前余额,用户可以看到他/她有多少余额!
显然,每当用户浏览我的网页应用页面时,必须执行以上查询以计算当前用户余额!
我想创建一个摘要表来获取当前用户余额,而无需在transactions
表上查询大约2000万条记录!
请注意,在我们的工作流程中,用户可能同时拥有多个交易(用户可能只需一秒钟就可以进行多次交易)
我认为我们有两种方法:
第一种方法
创建具有一对一关系的汇总表,如下所示:
ID | user_id | current_balance
1 | 1000 | 8590
2 | 1001 | 235
3 | 1002 | 3780
... | ... | ...
每次在transactions
表中插入新记录时,我们都会触发存储过程来更新摘要表中的用户current_balance
。
我不知道这种方法是否会破坏MySQL的一致性!
第二种方法
创建具有一对多关系的汇总表,如下所示:
ID | user_id | amount
1 | 1000 | 8590 <--- it's the initial user balance
2 | 1001 | 235 <--- it's the initial user balance
3 | 1002 | 3780 <--- it's the initial user balance
4 | 1000 | 50
5 | 1000 | -30
6 | 1001 | 10
7 | 1002 | 60
8 | 1000 | -45
我们每晚清除摘要表(例如在00:00 AM
)并从transactions
表重新计算所有用户的当前余额并将其插入摘要表。为了获得用户当前的平衡,我们只需要这样做:
SELECT sum(`amount`) FROM `users_balance` WHERE `user_id` = 1000;
但是有一些事情让我担心这种方法,如果有些用户在我们重新计算用户当前余额并将它们放入汇总表时完成交易呢? (恰好在00:00 AM
)
这种方法是否会破坏一致性?
如果您对此工作流程有任何更好的实践,请告诉我。
P.S:
我们的网络应用程序是一个SMS面板,用户可以直接通过面板或API发送/接收/等... SMS。我们有一些用户每天发送100万条或更多短信!
每次发送短信时,必须在transactions
表中插入新记录。
我知道2000万条记录并不是什么大问题,我们可以通过索引获得良好的性能,但正如我上面提到的,它是一个不断增长的表格。我很确定明年我们在transactions
表中会有数亿条记录。