MySQL程序 - 逐步重新计算行

时间:2016-03-20 08:16:28

标签: php mysql performance stored-procedures

我有一个非常简单的计算预算条目(收入/结果/余额)的任务。可以有数千个条目,我可以在中间更改任何条目。因此,必须重新计算所有后续条目的余额。

现在我通过遍历所有条目的数组并更新已更改的行来在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);
    }
}
你能指出正确的方向吗?谢谢!

2 个答案:

答案 0 :(得分:2)

我认为您可以在单个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不允许在多表ORDER BY查询中使用UPDATE,因此您需要加入一个以日期顺序生成ID的子查询。

答案 1 :(得分:0)

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

仅限“数千”,这不应该是性能问题。