优化了在对每一行运行一些计算后更新表中每一条记录的方式


Optimized ways to update every record in a table after running some calculations on each row

有一个大表,里面有数百万条记录。phpMyAdmin报告表的大小为1.2G。

每一行都需要进行一次计算。计算并不简单(不能放在set col=calc格式中),它使用一个存储函数来获取值,所以目前我们对每一行都有一个更新。

这是非常缓慢的,我们想优化它。

存储函数:
https://gist.github.com/a9c2f9275644409dd19d

此方法对每一行调用:
https://gist.github.com/82adfd97b9e5797feea6

这是在非实时服务器上执行的,通常每周更新一次。

我们有什么选择。

为什么不设置一个单独的表来保存计算值,以减轻当前表的负载。它可以有两列:主表中每行的主键和计算值的列。

那么您的流程可以是:

a) 截断computedValues表-这比尝试识别新行更快

b) 计算值并插入计算值表

c) 因此,当你需要计算值时,你可以使用主键连接到computedValues表,这很快,如果你需要更多的计算,你只需要添加新的列。

d) 如果必须进行

,也可以使用计算值更新主表

问题似乎不在于UPDATE查询,因为查询本身没有执行任何计算。看起来,首先执行计算,然后运行UPDATE查询。所以UPDATE应该足够快。

当您说"这非常慢"时,我认为您指的不是UPDATE查询,而是完整的过程。以下是一些快速的想法:

  1. 正如你所说,有数百万条记录,更新这么多条目总是很耗时的。如果表上定义了许多列和索引,则会增加开销。

  2. 我看到函数getNumberOfPeople()中有许多REPLACE INTO查询。这也可能是这个过程缓慢的一个原因。您检查过这些REPLACE INTO查询的效率吗?你能试着删除它们,然后看看它是否对UPDATE过程有任何影响吗。

  3. getNumberOfPeople()中也有几个SELECT查询。检查它们是否会影响流程,如果是,请尝试优化它们。

  4. 在过程updateGPCD()中,可以尝试用SELECT COUNT(1) INTO _has_breakdown替换SELECT COUNT(*) INTO _has_breakdown。在同一个查询中,WHERE条件正在读取_ACCOUNT,但当_ACCOUNT=0时,这将失败,否?

根据另一个建议,如果您认为UPDATE由于原因1而速度较慢,那么将更新列gpcdusage_bill移到另一个表可能是有意义的。表中唯一的其他列应该是来自usage_bill的唯一ID。

希望以上内容有意义。