skip to Main Content

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 :

  • WAMP SERVER 3.1.4
  • PHP 7.2.10
  • MYSQL 5.7.23

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();
    }

2

Answers


  1. 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…

    The Problem

    Your code isn’t easy to follow, however, I believe the gist of the issue is that:

    1. Your database has been corrupted in some way and fields client_oldfunds and client_newfunds no longer hold the correct data.

    2. 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?

    Database

    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
    

    Code

    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.

    Login or Signup to reply.
  2. 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);
        }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search