【发布时间】:2017-05-08 11:27:43
【问题描述】:
我有一个名为 transactions 的表,其中包含大约 2000 万条记录。该表每秒都在增长。
我计算用户当前余额:
SELECT sum(`amount`) FROM `transactions` WHERE `user_id` = 1000;
我在我的网络应用程序的顶部栏中显示用户当前的余额,用户可以看到他/她有多少余额!
显然每次用户浏览我的网页应用页面时,都必须执行上述查询来计算当前的用户余额!
我想创建一个汇总表来获取当前用户余额,而无需查询具有约 2000 万条记录的 transactions 表!
请注意,在我们的工作流程中,用户可能同时进行多项交易非常常见(用户甚至可能在一秒钟内完成多项交易)。
我认为我们在这里有两种方法:
第一种方法
创建一个具有一对一关系的汇总表,如下所示:
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)
这种方法会破坏一致性吗?
如果您知道此工作流程的更好做法,请告诉我。
附言
我们的网络应用程序是一个短信面板,用户可以通过它发送/接收/等。通过面板直接发送短信或通过 API。我们有一些用户一天发送 100 万条或更多短信!
每次发送 SMS 时,都必须在 transactions 表中插入一条新记录。
我知道 2000 万条记录没什么大不了的,我们可以通过索引实现良好的性能,但正如我上面提到的,它是一个不断增长的表。我很确定明年我们将在transactions 表中拥有数亿条记录。
【问题讨论】:
-
1.在顶部栏中向用户提供稍微不准确(稍微过时)的余额会产生什么后果?你的申请允许吗? 2. 您是否在
(userid, amount)上创建了复合索引并测量了您的SUM()查询的性能?如果索引正确,二十兆行并不是很多。您实际上可能不需要汇总表, -
我认为这需要专业的帮助。
-
@O.Jones 查看更新
-
@O.Jones 如果我们显示的余额有点不准确,用户可以在余额不足时发送短信!因为在用户发送短信之前,我们会检查用户余额。
-
@HamedKamrava - 没关系;使用 OJoine 的
transactions和balances表;它可能会更好。
标签: mysql sql database database-design