PHP 函数执行时间过长
PHP function execution time taking long
我写的功能不错;我猜,但是当我在有很多事务的客户端上使用这个函数时,它需要 20 秒,每次添加新事务时都会增加。此功能从一开始就开始重新计算所有客户债务。
我正在使用:
- WAMP 服务器 3.1.4
- PHP 7.2.10
- MYSQL 5.7.23
我尝试了 php.ini
中的一些更改
php.ini
post_max_size = 256M
upload_max_filesize = 128M
memory_limit = 1G
max_input_vars = 10000
和
my.ini
key_buffer_size = 256M
max_allowed_packet = 128M
sort_buffer_size = 128M
net_buffer_length = 8K
read_buffer_size = 128M
read_rnd_buffer_size = 128M
myisam_sort_buffer_size = 512M
innodb_buffer_pool_size = 256M
innodb_log_file_size = 256M
innodb_log_buffer_size = 512M
[mysqldump]
quick
max_allowed_packet = 512M
[isamchk]
key_buffer_size = 512M
sort_buffer_size = 128M
read_buffer_size = 256M
write_buffer_size = 256M
[myisamchk]
key_buffer_size = 512M
sort_buffer_size_size = 512M
read_buffer_size = 256M
write_buffer_size = 256M
这里是函数
function reCalculateAll($conn, $clid, $cltp){
$stmt = $conn->prepare("SELECT * FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt->bind_param('is', $clid, $cltp);
$stmt->execute();
$results = $stmt->get_result();
$stmt->fetch();
$numberofrows = $stmt->num_rows;
while ($row = $results->fetch_assoc()) {
$r = getAllTransactionsClient($conn, $clid, $cltp);
$result = array();
foreach($r as $i => $p){
$result[$p['client_type'].$p['client_id']][] = $p;
foreach ($result as $rr){
foreach ($rr as $c => $k){
reset($rr);
$trid = $k['id'];
$trcn = $k['client_id'];
$trtp = $k['client_type'];
$trdt = $k['transaction_date'];
if($c === key($rr)){
// FIX TRANSACTION
$addm = 0;
$stmtf = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? + added_amount where id = ?");
$stmtf->bind_param('ssi', $addm, $addm, $trid);
$stmtf->execute();
$stmtf->close();
$addm = $k['client_newfunds'];
} else {
$stmtn = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? + added_amount where id = ?");
$stmtn->bind_param('ssi', $addm, $addm, $trid);
$stmtn->execute();
$stmtn->close();
$addm = $k['client_newfunds'];
}
$cnf = getLastDebtFromTransaction($conn, $trtp, $trcn);
setDebts($conn, $trtp, $cnf, $trcn);
}
}
}
}
$results->free();
$stmt->execute();
$stmt->store_result();
$numberofrows = $stmt->num_rows;
if($numberofrows == 0){
setDebts($conn, $cltp, '0', $clid);
}
$stmt->close();
}
getAllTransactionsClient 函数
function getAllTransactionsClient($conn, $clid, $cltp){
$stmt = $conn->prepare("SELECT * FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt->bind_param('is', $clid, $cltp);
$stmt->execute();
$result = $stmt->get_result();
$products = array();
while ($row = $result->fetch_assoc()) {
$products[] = $row;
}
return $products;
$stmt->close();
}
前导
我将跳过“回答您的问题”——我认为上面的评论中突出了很多问题——直接进入我认为您希望代码执行的解决方案。 ..
问题
您的代码不容易理解,但是,我认为问题的要点是:
您的数据库已以某种方式损坏,字段 client_oldfunds
和 client_newfunds
不再包含正确的数据。
您相信字段 added_amount
是正确的并且想返回并为每笔交易重新计算上面的字段以便全部计算正确吗?
数据库
Table结构
CREATE TABLE transactions (
id bigint AUTO_INCREMENT PRIMARY KEY,
client_id bigint,
client_type varchar(20),
client_oldfunds decimal(10,2),
client_newfunds decimal(10,2),
added_amount decimal(10,2),
transaction_date varchar(20)
);
示例当前数据
假设这里的交易是按日期排序的。
id | client_id | client_type | client_oldfunds | client_newfunds | added_amount
--- | ----------- | ------------- | ----------------- | ----------------- | --------------
1 | 1 | type_a | 12.10 | 1.36 | 3.12
2 | 1 | type_a | 6.00 | 432.42 | 4.50
3 | 1 | type_a | 30.12 | 1.33 | 100.22
4 | 1 | type_a | 23.1 | 1.22 | 10.2
5 | 1 | type_a | 123.4 | 55.54 | 12.6
示例正确数据
假设这里的交易是按日期排序的。
id | client_id | client_type | client_oldfunds | client_newfunds | added_amount
--- | ----------- | ------------- | ----------------- | ----------------- | --------------
1 | 1 | type_a | 0 | 3.12 | 3.12
2 | 1 | type_a | 3.12 | 7.62 | 4.50
3 | 1 | type_a | 7.62 | 107.84 | 100.22
4 | 1 | type_a | 107.84 | 118.04 | 10.2
5 | 1 | type_a | 118.04 | 130.64 | 12.6
代码
我们希望它做什么
reCalculateAll{
0 > Initialise a balance of 0
1 > SELECT id and amount_added for all related transactions, in order
2 > UPDATE the client_oldfunds to the balance and client_newfunds to the balance + the added_amount
3 > UPDATE the balance to the new value (balance + added_amount)
}
实际代码
function reCalculateAll($mysqli, $client_id, $client_type){
$select_sql = "
SELECT id, added_amount
FROM transactions
WHERE client_id = ?
AND client_type = ?
ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC
";
$select_query = $mysqli->prepare($select_sql);
$select_query->bind_param("is", $client_id, $client_type);
$select_query->execute();
$select_query->store_result();
$select_query->bind_result($transaction_id, $added_amount);
$old_balance = 0;
while($select_query->fetch()){
$new_balance = $old_balance + $added_amount;
$update_sql = "
UPDATE transactions
SET client_oldfunds = ?,
client_newfunds = ?
WHERE id = ?
";
$update_query = $mysqli->prepare($update_sql);
$update_query->bind_param("ssi", $old_balance, $new_balance, $transaction_id);
$update_query->execute();
$old_balance = $new_balance;
}
}
N.B.
您确实应该以 MySQL 格式“Y-m-d H:i:s”存储您的日期。它使排序更容易;当日期输出到浏览器时应该进行格式化。
你的代码需要改进,我看到一个里面有多个循环,
这是你的第一个功能,你可以去掉最后一个,因为它有点没用。
实际函数应该是这样的:
function reCalculateAll($conn, $client_id, $client_type){
// THE FOLLOWING QUERY WILL REPLACE this function for you getAllTransactionsClient();
$stmt = $conn->prepare("SELECT id, added_amount FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt -> bind_param("is", $client_id, $client_type);
$stmt -> execute();
$stmt -> store_result();
$stmt -> bind_result($transaction_id, $added_amount);
// THIS $oldfunds stands for your old $addm
$oldfunds = 0;
while($stmt->fetch()){
$newfunds = $oldfunds + $added_amount;
$stmtd = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? WHERE id = ?");
$stmtd->bind_param("ssi", $oldfunds, $newfunds, $transaction_id);
$stmtd->execute();
$oldfunds = $newfunds;
}
$stmt->close();
// this should send 0 if there is no transactions
setDebts($conn, $client_type, $oldfunds, $client_id);
}
我写的功能不错;我猜,但是当我在有很多事务的客户端上使用这个函数时,它需要 20 秒,每次添加新事务时都会增加。此功能从一开始就开始重新计算所有客户债务。 我正在使用:
- WAMP 服务器 3.1.4
- PHP 7.2.10
- MYSQL 5.7.23
我尝试了 php.ini
中的一些更改php.ini
post_max_size = 256M
upload_max_filesize = 128M
memory_limit = 1G
max_input_vars = 10000
和
my.ini
key_buffer_size = 256M
max_allowed_packet = 128M
sort_buffer_size = 128M
net_buffer_length = 8K
read_buffer_size = 128M
read_rnd_buffer_size = 128M
myisam_sort_buffer_size = 512M
innodb_buffer_pool_size = 256M
innodb_log_file_size = 256M
innodb_log_buffer_size = 512M
[mysqldump]
quick
max_allowed_packet = 512M
[isamchk]
key_buffer_size = 512M
sort_buffer_size = 128M
read_buffer_size = 256M
write_buffer_size = 256M
[myisamchk]
key_buffer_size = 512M
sort_buffer_size_size = 512M
read_buffer_size = 256M
write_buffer_size = 256M
这里是函数
function reCalculateAll($conn, $clid, $cltp){
$stmt = $conn->prepare("SELECT * FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt->bind_param('is', $clid, $cltp);
$stmt->execute();
$results = $stmt->get_result();
$stmt->fetch();
$numberofrows = $stmt->num_rows;
while ($row = $results->fetch_assoc()) {
$r = getAllTransactionsClient($conn, $clid, $cltp);
$result = array();
foreach($r as $i => $p){
$result[$p['client_type'].$p['client_id']][] = $p;
foreach ($result as $rr){
foreach ($rr as $c => $k){
reset($rr);
$trid = $k['id'];
$trcn = $k['client_id'];
$trtp = $k['client_type'];
$trdt = $k['transaction_date'];
if($c === key($rr)){
// FIX TRANSACTION
$addm = 0;
$stmtf = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? + added_amount where id = ?");
$stmtf->bind_param('ssi', $addm, $addm, $trid);
$stmtf->execute();
$stmtf->close();
$addm = $k['client_newfunds'];
} else {
$stmtn = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? + added_amount where id = ?");
$stmtn->bind_param('ssi', $addm, $addm, $trid);
$stmtn->execute();
$stmtn->close();
$addm = $k['client_newfunds'];
}
$cnf = getLastDebtFromTransaction($conn, $trtp, $trcn);
setDebts($conn, $trtp, $cnf, $trcn);
}
}
}
}
$results->free();
$stmt->execute();
$stmt->store_result();
$numberofrows = $stmt->num_rows;
if($numberofrows == 0){
setDebts($conn, $cltp, '0', $clid);
}
$stmt->close();
}
getAllTransactionsClient 函数
function getAllTransactionsClient($conn, $clid, $cltp){
$stmt = $conn->prepare("SELECT * FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt->bind_param('is', $clid, $cltp);
$stmt->execute();
$result = $stmt->get_result();
$products = array();
while ($row = $result->fetch_assoc()) {
$products[] = $row;
}
return $products;
$stmt->close();
}
前导
我将跳过“回答您的问题”——我认为上面的评论中突出了很多问题——直接进入我认为您希望代码执行的解决方案。 ..
问题
您的代码不容易理解,但是,我认为问题的要点是:
您的数据库已以某种方式损坏,字段
client_oldfunds
和client_newfunds
不再包含正确的数据。您相信字段
added_amount
是正确的并且想返回并为每笔交易重新计算上面的字段以便全部计算正确吗?
数据库
Table结构
CREATE TABLE transactions (
id bigint AUTO_INCREMENT PRIMARY KEY,
client_id bigint,
client_type varchar(20),
client_oldfunds decimal(10,2),
client_newfunds decimal(10,2),
added_amount decimal(10,2),
transaction_date varchar(20)
);
示例当前数据
假设这里的交易是按日期排序的。
id | client_id | client_type | client_oldfunds | client_newfunds | added_amount
--- | ----------- | ------------- | ----------------- | ----------------- | --------------
1 | 1 | type_a | 12.10 | 1.36 | 3.12
2 | 1 | type_a | 6.00 | 432.42 | 4.50
3 | 1 | type_a | 30.12 | 1.33 | 100.22
4 | 1 | type_a | 23.1 | 1.22 | 10.2
5 | 1 | type_a | 123.4 | 55.54 | 12.6
示例正确数据
假设这里的交易是按日期排序的。
id | client_id | client_type | client_oldfunds | client_newfunds | added_amount
--- | ----------- | ------------- | ----------------- | ----------------- | --------------
1 | 1 | type_a | 0 | 3.12 | 3.12
2 | 1 | type_a | 3.12 | 7.62 | 4.50
3 | 1 | type_a | 7.62 | 107.84 | 100.22
4 | 1 | type_a | 107.84 | 118.04 | 10.2
5 | 1 | type_a | 118.04 | 130.64 | 12.6
代码
我们希望它做什么
reCalculateAll{
0 > Initialise a balance of 0
1 > SELECT id and amount_added for all related transactions, in order
2 > UPDATE the client_oldfunds to the balance and client_newfunds to the balance + the added_amount
3 > UPDATE the balance to the new value (balance + added_amount)
}
实际代码
function reCalculateAll($mysqli, $client_id, $client_type){
$select_sql = "
SELECT id, added_amount
FROM transactions
WHERE client_id = ?
AND client_type = ?
ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC
";
$select_query = $mysqli->prepare($select_sql);
$select_query->bind_param("is", $client_id, $client_type);
$select_query->execute();
$select_query->store_result();
$select_query->bind_result($transaction_id, $added_amount);
$old_balance = 0;
while($select_query->fetch()){
$new_balance = $old_balance + $added_amount;
$update_sql = "
UPDATE transactions
SET client_oldfunds = ?,
client_newfunds = ?
WHERE id = ?
";
$update_query = $mysqli->prepare($update_sql);
$update_query->bind_param("ssi", $old_balance, $new_balance, $transaction_id);
$update_query->execute();
$old_balance = $new_balance;
}
}
N.B.
您确实应该以 MySQL 格式“Y-m-d H:i:s”存储您的日期。它使排序更容易;当日期输出到浏览器时应该进行格式化。
你的代码需要改进,我看到一个里面有多个循环, 这是你的第一个功能,你可以去掉最后一个,因为它有点没用。
实际函数应该是这样的:
function reCalculateAll($conn, $client_id, $client_type){
// THE FOLLOWING QUERY WILL REPLACE this function for you getAllTransactionsClient();
$stmt = $conn->prepare("SELECT id, added_amount FROM transactions WHERE client_id = ? AND client_type = ? ORDER BY STR_TO_DATE(transaction_date, '%d/%m/%Y %H:%i:%s') ASC");
$stmt -> bind_param("is", $client_id, $client_type);
$stmt -> execute();
$stmt -> store_result();
$stmt -> bind_result($transaction_id, $added_amount);
// THIS $oldfunds stands for your old $addm
$oldfunds = 0;
while($stmt->fetch()){
$newfunds = $oldfunds + $added_amount;
$stmtd = $conn->prepare("UPDATE transactions SET client_oldfunds = ?, client_newfunds = ? WHERE id = ?");
$stmtd->bind_param("ssi", $oldfunds, $newfunds, $transaction_id);
$stmtd->execute();
$oldfunds = $newfunds;
}
$stmt->close();
// this should send 0 if there is no transactions
setDebts($conn, $client_type, $oldfunds, $client_id);
}