在 MySQL 中为不断增长的表创建汇总表的最佳实践

Ham*_*ava 5 mysql sql database database-design

我有一张桌子叫 transactions有大约 2000 万条记录。该表每秒增长。

我计算用户当前余额:

SELECT sum(`amount`) FROM `transactions` WHERE `user_id` = 1000;
Run Code Online (Sandbox Code Playgroud)

我在我的 Web 应用程序的顶部栏中显示用户当前余额,用户可以看到他/她有多少余额!

显然,每次用户浏览我的网页应用时,都必须执行上述查询来计算当前用户余额!

我想创建一个汇总表来获取当前用户余额而不查询 transactions表上大约 2000 万条记录!

请注意,在我们的工作流程中,一个用户可能同时有多个事务(一个用户甚至可能在一秒钟内有多个事务)是如此普遍。

我认为我们在这里有两种方法:

第一种方法

创建具有一对一关系的汇总表,如下所示:

ID  |  user_id  |  current_balance
1   |  1000     |      8590
2   |  1001     |      235
3   |  1002     |      3780
... |  ...      |      ...
Run Code Online (Sandbox Code Playgroud)

并且每次将新记录插入到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
Run Code Online (Sandbox Code Playgroud)

我们每晚清除我们的汇总表(例如在00:00 AM)并重新计算transactions表中所有用户的当前余额并将它们插入到汇总表中。要确定用户的当前余额,我们只需要执行以下操作:

SELECT sum(`amount`) FROM `users_balance` WHERE `user_id` = 1000;
Run Code Online (Sandbox Code Playgroud)

但是有一点让我担心这种方法。如果某些用户恰好在我们重新计算用户当前余额并将其放入汇总表的时间进行交易,该怎么办!(正好在00:00 AM

这种方法会破坏一致性吗?


请告诉我您是否知道此工作流程的任何更好的做法。

聚苯乙烯

我们的网络应用程序是一个短信面板,用户可以通过它发送/接收/等。直接通过面板或 API 发送短信。我们有一些用户一天发送100万条或更多的短信!

每次发送短信时,都必须在transactions表中插入一条新记录。

我知道 2000 万条记录并不是什么大问题,我们可以通过索引实现良好的性能,但正如我上面提到的,它是一个不断增长的表。我很确定明年我们将有数亿条记录transactions

Shi*_*wal 0

在我看来,您的第一种方法看起来很酷,但我认为您只需要根据交易计算新值(例如,如果是贷记/借记)。

但是,为什么您每次都访问数据库,而是可以使用会话变量来维护相同的数据并使用同步,同时使用该金额进行任何交易并在汇总表中更新相同的数据。

您还应该使用数据库索引、绑定变量[在应用程序中]来提高性能。

(如果您不想做所有这些事情,一个非常简单的解决方案是分区。您可以使用索引和绑定变量[在应用程序中]在事务表上创建日期分区,这将完成您想要实现的相同操作与上述两种方法。)

您的第二种方法有很多问题,例如重新计算的数据库开销,这可能会降低/减慢您的应用程序,并且您再次以某种方式进行计算。