MySQL 过程 - 以增量方式重新计算行


MySQL procedures - incrementally recalculate rows

>我有一个相当微不足道的任务来计算预算条目(收入/结果/余额)。可以有数千个条目,我可以在中间更改其中任何一个。因此,必须重新计算所有以后的条目余额。

现在,我正在通过遍历所有条目的数组并更新更改的行来在PHP中执行此操作。这样花费的时间太多了 - 我的服务器停止响应几分钟。

我想这是因为 PHP 为每个条目更新调用 MySQL,尽管对于 PHP 本身来说,数组迭代和重新计算的任务非常便宜。我认为必须有一种方法可以将此任务扔给MySQL,因此它自己进行迭代/重新计算/更新,这可能也很便宜。

我根本不是MySQL的专家,但我听说有一些存储过程可能是治愈的方法。

这是我的MySQL(5.5.33)表:

CREATE TABLE `entry` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `date` date DEFAULT NULL,
  `is_income` tinyint(1) NOT NULL DEFAULT '0',
  `income` decimal(20,2) DEFAULT NULL,
  `outcome` decimal(20,2) DEFAULT NULL,
  `balance` decimal(20,2) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

这是我的PHP(5.3.27):

//...
//$DB is a class for operating DB
$entries = $DB->get_all('entry'); //retrieves all entries from 'entry' table, sorted by date
$balance = 0;
foreach ($entries as $e) {
    if ($e['is_income']) {
        $balance += $e['income'];
    } else {
        $balance -= $e['outcome'];
    }
    if ($balance <> $e['balance']) {
        $e1 = $e;
        $e1['balance'] = $balance;
        $DB->update('entry', $e1); //update the row by doing query('UPDATE `entry` ... WHERE id=' . $entry_id);
    }
}

你能指出我正确的方向吗?谢谢!

我认为您可以在单个 SQL UPDATE查询中执行此操作,无需任何过程。

UPDATE entry AS e1
JOIN (SELECT * FROM entry ORDER BY date) AS e2 ON e1.id = e2.id
CROSS JOIN (SELECT @balance := 0) AS var
SET e1.balance = (@balance := @balance + IF(e2.is_income, e2.income, -e2.outcome))

用户变量@balance与 PHP 变量 $balance 具有相同的目的。子查询是必需的,因为MySQL不允许在多表UPDATE查询中使用ORDER BY,因此您需要与按日期顺序生成ID的子查询联接。

"正确"的方法是在显示报告时进行求和,而不是将其存储在表中。

对于仅"数千",它不应该是性能问题。