Reputation: 55
I have a good written function; I guess, but when I use this function on a client that has many transactions it takes like 20 seconds, increasing everytime I add new transaction. This functions starts recounting all client debts since the beginning. I am using :
I have tried some changes in php.ini
php.ini
post_max_size = 256M
upload_max_filesize = 128M
memory_limit = 1G
max_input_vars = 10000
and
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
and here's the function
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
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();
}
Upvotes: 2
Views: 190
Reputation: 363
Your code needs improving, I see that there are multiple loops in one, Here's your first function, you can get rid of the last one because it is kinda useless.
Actual function should be like this:
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);
}
Upvotes: 2
Reputation: 6148
Pre-cursor
I'm going to skip over "answering your question" - I think a lot of the problems are highlighted in the comments above - and move straight in to a solution for what I think you intend your code to do...
Your code isn't easy to follow, however, I believe the gist of the issue is that:
Your database has been corrupted in some way and fields client_oldfunds
and client_newfunds
no longer hold the correct data.
You trust the field added_amount
is correct and want to go back and recalculate the fields above for each transaction so that it all tallies up?
Table Structure
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)
);
Example Current Data
Assume that the transactions here are ordered by date.
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
Example Correct Data
Assume that the transactions here are ordered by date.
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
What we want it to do
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)
}
Actual Code
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.
You really should be storing your dates in the MySQL format "Y-m-d H:i:s". It makes sorting easier; formatting should happen when the date is output to the browser.
Upvotes: 2