我有一个非常简单的计算预算条目(收入/结果/余额)的任务。可以有数千个条目,我可以在中间更改任何条目。因此,必须重新计算所有后续条目的余额。
现在我通过遍历所有条目的数组并更新已更改的行来在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);
}
}
你能指出正确的方向吗?谢谢!
答案 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)
“正确”的方式是在显示报告时进行求和,而不是将其存储在表格中。
仅限“数千”,这不应该是性能问题。