Trying to compress and make my code faster

I apologize for the length of my script. Is there a better way to do some of what I am doing here? My script is working fine but it works off a lot of data and if I try to query all the results, the response is pretty slow (1500ms).

I’m concerned about that length of time when it comes to multiple users hitting the server at once. I may have to limit the query with pagination, etc. But, I just have a feeling there’s a better way to do what I’m doing without over 1,000 lines…

https://pastebin.com/JeM4Y7vZ

I had to pastebin the code because it was too long to post.

So, the code could easily be cut down, it has bloat without benefiting from it.
Your query is exceptionally simple, but you should not be doing SELECT *, you should name the columns you want explicitly.

Other than that, have you actually identified bottlenecks? What is your SLA agreement?

You have 90% more code than you need. Create a function for the button.

SLA agreement? I’m unfamiliar with that term.

Service Level Agreement. It states uptime and latency for a given task. For instance,
if your SLA says >5 seconds for 90% of operations, you are fine. If it is >1 second it isn’t (nor is it realistic).

I see. I don’t have any agreement but I just thought about how slow it would be when multiple users are trying to access it. I thought if it is taking 1500ms now for just me it could be much worse down the road. But, I wasn’t sure. The get_user_dept and get_order_status each do DB queries.

Is there a way to not have to perform them over and over several thousand times?

I was thinking the same thing.

Will those query results change? How frequently?

Why is line_item not already trimmed as it sits in the DB? Running TRIM in the query is likely slowing you down.

I also suggest you attempt real load testing before you think you have an issue that you really don’t. How many concurrent users are you realistically expecting? Not hoping for but actually expect.

@astonecipher The user’s department code will not change very often at all. Also, what do you mean by a read load test? I expect 15-16 people to hit that code pretty often for sure and I would like for it to refresh on an interval via ajax if they have it open on their screens. In the future that data may be displayed on TV screens and need to refresh often. The machine hosting it is a dedicated box out of our Chicago office (I’m in Texas as are the users that will be using it) only accessible internally via the network or VPN. Box specs are as follows: Xeon E31220/16GB RAM/1TB HD

What do you think about these specs? The data in production_data table will be updated nightly via a scheduled job that takes data from a CSV which is dumped from another source. Other scheduled jobs will run throughout the day as well (though I will push as many to the night as possible)

@benanamen I am working off a temporary dataset I quickly imported into the DB a little over a month ago. I forgot to trim the data and there was whitespace in there that was causing an issue. I plan to fix that with the new import function I will write but I didn’t realize that TRIM in a SQL statement could be so intensive

For trimming the data, use one UPDATE query to trim it in the table, all at once.

Code must be readable and maintainable. Also, Don’t Repeat Yourself (DRY.) ALL that conditional logic, written out for every combination of the input values, can be replaced with the following -

<?php

// inputs are the current user's dept code (1-10), the current status (0-3) for each button x 5 buttons
// there are also per row $id, $job_number, and $enterprise values
// output is 5 buttons, which can be in one of 4 states, and either enabled or disabled depending on the dept match
// dept match 1,2,3 - all, same dept

// create test data, produced by the existing code
$user_dept_code = 1;  // note this code works for the special '7,8' case too
$id = 12;
$job_number = 23;
$enterprise = 34;

// alter your existing code to store the status as an array, with the department code as the index
$status[10] = 0;
$status[6] = 1;
$status[5] = 2;
$status[7] = 3;
$status[8] = 0;

// define output button array
$btn = [];

// produce the buttons
foreach($status as $dept=>$stat)
{
	// enabled if user dept is 1,2,3 or the current dept matches the user's dept
	$enabled = in_array($user_dept_code,[1,2,3]) || in_array($dept,explode(',',$user_dept_code)) ? '' : ' disabled';

	// populate the dynamic values. you should actually use a template here with replaceable tags, then only produce the button that matches the current status value
	$buttons[1] = "<button type='button' class='btn btn-warning btn-sm btn_change_order_status_dialog' style='margin:0; width: 100px; height:100%; font-weight: bold;' data-order-id='$id' data-order-number='$job_number' data-order-enterprise='$enterprise' data-dept-code='$dept'$enabled>In Progress</button>";
	$buttons[2] = "<button type='button' class='btn btn-danger btn-sm btn_change_order_status_dialog' style='margin:0; width: 100px; height:100%; font-weight: bold;' data-order-id='$id' data-order-number='$job_number' data-order-enterprise='$enterprise' data-dept-code='$dept'$enabled>Delayed</button>";
	$buttons[3] = "<button type='button' class='btn-success btn-sm btn_change_order_status_dialog' style='margin:0; width: 100px; height:100%; font-weight: bold;' data-order-id='$id' data-order-number='$job_number' data-order-enterprise='$enterprise' data-dept-code='$dept'$enabled>Finished</button>";
	$buttons[0] = "<button type='button' class='btn btn-secondary btn-sm btn_change_order_status_dialog' style='margin:0; width: 100px; height:100%; font-weight: bold;' data-order-id='$id' data-order-number='$job_number' data-order-enterprise='$enterprise' data-dept-code='$dept'$enabled>Not Started</button>";

	// get the button that matches the current status value for each dept
	$btn[$dept] = $buttons[$stat];
}

// examine the results
echo '<pre>';
print_r($btn);

Since this code only has one instance of any element, making changes or corrections can be done in just one place.

1 Like

< 20 users is nothing for a user base so that isn’t an actual issue. What you do need to focus on is cleaning up the code first. Until there is a slowness issue, don’t worry about pre-optimizations, you don’t know where your bottlenecks are so don’t guess.

Your massive switch statements need refactoring badly. I would guess a lot of the other code does as well? That’s a primary focus.

Secondary, sql queries. Remove all of the select all, name the columns you are requesting. If there are any queries that have a slow fetch time (direct not through a code interface) run an explain to profile it and see where it can be optimized. Indexes will speed up a query, but used inefficiently they can drastically increase the query time as well.

If it is performing the exact same query repeatedly, you can cache the results with an expiration date. Prepared statements help this if you are running the same query in the same session, because it doesn’t have to prep the query before each run, it’s done initially and ran as needed thereafter.

Freaking genius! Ugh…I wish I was better with arrays sometimes. I’m playing with this now and figuring it all out. What do you mean when you say you should actually use a template here with replaceable tags

Are you saying to make another function in PHP?

An array is simply a list. Think of a shopping list you have probably used all your life.

Basic Array…

Milk
Bread
Juice
Chicken

Multi-Dimensional Array…

MEAT
Chicken
Steak

DRINKS
Milk
Juice
Soda

FRUIT
Apples
Pears
Bananas

Yea I gotcha. I think the biggest problem I have is constructing and analyzing them. Say if I wanted to resort a complex multidimentional array, etc.

One example, I’m having trouble understanding the difference between…say…:

if ( !isset( $statuses[ $row[ "order_id" ] ] ) ) {
	$statuses[ $row[ "order_id" ] ] = [];
}

VS…

   if ( !isset( $statuses[ $row[ "order_id" ] ] ) ) {
    	$statuses[$row[ "order_id" ]][];
    }

Is there any difference here?

One you are assigning as an array, the other isn’t doing anything.

Okay, I’m trying to do an in_array()…it’s not working.

Array
(
    [75333] => Array
        (
            [5] => 3
            [7] => 2
            [6] => 2
        )

    [75348] => Array
        (
            [8] => 2
            [6] => 2
        )

    [75340] => Array
        (
            [7] => 3
            [6] => 1
            [5] => 3
        )

    [75352] => Array
        (
            [5] => 1
        )

)

And I’m doing:

if ( in_array ( '75352', $statuses ) ) {
    echo 'TRUE<br>';
}

But I never get it to say true. The value is in the array though?

How does this look? I’ve spent all day on it lol. It’s definitely faster and more responsive. 1300 lines of code cut down to roughly 200!

session_start();
include('dbconfig.php');

	
$query = "
			SELECT p1.order_id, p1.dept_code, p1.status_id
			FROM production_status p1
			LEFT JOIN production_status p2 ON -- find similar records
			  p1.order_id = p2.order_id AND   -- ...for the same order
			  p1.dept_code = p2.dept_code AND -- ...and the same department
			  p2.submit_time > p1.submit_time -- ...and that come after the row that p1 found
			WHERE
			  p1.dept_code IN (5, 6, 7, 8, 10) AND -- limit to department we care about
			  p2.id IS NULL                        -- filter to keep only the p1 rows that didn't have later p2 rows
		 ";

$statement = $pdo->prepare( $query );
$statement->execute();

//store results in array
$result = $statement->fetchAll();

//array to store order statuses
$statuses = [];

//build array to store order statuses for each order that has a manufacturing status
foreach ( $result as $row ) {

	//check to see if the order id already exists in $statuses array, if not create it
	if ( !isset( $statuses[ $row[ "order_id" ] ] ) ) {
		$statuses[ $row[ "order_id" ] ] = [];
	}

	$statuses[ $row[ "order_id" ] ][ $row[ "dept_code" ] ] = $row[ "status_id" ];
}

/*fetch production data*/
//setup query
$sql = 'SELECT * FROM production_data ORDER BY enterprise, job_number, line_item ASC';

//execute SQL transaction
try {
	//prepare SQL statement & execute
	$stmt = $pdo->prepare($sql);
	$stmt->execute();

	//bind column names to variables
	$stmt->bindColumn('id', $id);
	$stmt->bindColumn('job_number', $job_number);
	$stmt->bindColumn('enterprise', $enterprise);
	$stmt->bindColumn('part_number', $part_number);
	$stmt->bindColumn('description', $description);
	$stmt->bindColumn('qty', $qty);
	$stmt->bindColumn('line_item', $line_item);
	$stmt->bindColumn('as400_ship_date', $as400_ship_date);
	$stmt->bindColumn('date_showed_on_report', $date_showed_on_report);
	$stmt->bindColumn('shipping_method', $shipping_method);
	$stmt->bindColumn('notes', $notes);
	$stmt->bindColumn('date_shown_complete', $date_shown_complete);
	$stmt->bindColumn('actual_ship_date', $actual_ship_date);
	$stmt->bindColumn('qty_shipped', $qty_shipped);

	//store user dept code
	$user_dept_code = get_user_dept( $_SESSION[ 'user_id' ], $pdo );

	$test_results = [];



	//output data into spreadsheet view
	while($row = $stmt->fetch(PDO::FETCH_BOUND)) {

		$order_statuses = [];

		//order has manufacturing status updates
		if( isset ( $statuses[ $id ] ) ) {

			if ( !isset ( $order_statuses[ $id ] ) ) {
				$order_statuses[ $id ] = [];
			}

			//check vinyl & paint status
			if ( isset ( $statuses[ $id ][ 5 ] ) ) {
				$order_statuses[$id][ 5 ] = $statuses[ $id ][ 5 ];
			} else { 
				$order_statuses[ $id ][ 5 ] = 0;
			}

			//check thermoforming status
			if ( isset ( $statuses[ $id ][ 6 ] ) ) {
				$order_statuses[$id][ 6 ] = $statuses[ $id ][ 6 ];
			} else { 
				$order_statuses[ $id ][ 6 ] = 0;
			}

			//check final assembly status
			if ( isset ( $statuses[ $id ][ 7 ] ) ) {
				$order_statuses[$id][ 7 ] = $statuses[ $id ][ 7 ];
			} else { 
				$order_statuses[ $id ][ 7 ] = 0;
			}

			//check crating & shipping status
			if ( isset ( $statuses[ $id ][ 8 ] ) ) {
				$order_statuses[$id][ 8 ] = $statuses[ $id ][ 8 ];
			} else { 
				$order_statuses[ $id ][ 8 ] = 0;
			}

			//check quality control status
			if ( isset ( $statuses[ $id ][ 10 ] ) ) {
				$order_statuses[$id][ 10 ] = $statuses[ $id ][ 10 ];
			} else { 
				$order_statuses[ $id ][ 10 ] = 0;
			}	

		//order has no manufacturing status updates
		} else {

			if ( !isset ( $order_statuses[ $id ] ) ) {
				$order_statuses[ $id ] = [];
			}

			$order_statuses[ $id ][ 5 ] = 0;
			$order_statuses[ $id ][ 6 ] = 0;
			$order_statuses[ $id ][ 7 ] = 0;
			$order_statuses[ $id ][ 8 ] = 0;
			$order_statuses[ $id ][ 10 ] = 0;

		}

		//build JSON response
		if ( !isset($json[$job_number]))  {
			$json[$job_number] = array(
				'Enterprise' => $enterprise,
				'Job Number' => $job_number,
				'LN #' => null,
				'AS400 Ship' => null,
				'Est. Ship' => null,
				'Q.C.' => null,
				'Thermoforming' => null,
				'Vinyl/Paint' => null,
				'Final Assembly' => null,
				'Crating/Shipping' => null,
			);
		}
		$json[$job_number]['__children'][] = array(
				//'LN #' => $line_item,
				'LN #' => '<a href="order_details.php?order=' . $id . '">' . $line_item . '</a>',
				'Description' => $description,
				'AS400 Ship Date' => $as400_ship_date,
				'Est. Ship' => '12/12/1801',
				'Q.C.' => build_change_order_status_btns($id, $user_dept_code, $job_number, $enterprise, $order_statuses[ $id ])[10],
				'Thermoforming' => build_change_order_status_btns($id, $user_dept_code, $job_number, $enterprise, $order_statuses[ $id ])[6],
				'Vinyl/Paint' => build_change_order_status_btns($id, $user_dept_code, $job_number, $enterprise, $order_statuses[ $id ])[5],
				'Final Assm.' => build_change_order_status_btns($id, $user_dept_code, $job_number, $enterprise, $order_statuses[ $id ])[7],
				'Crating/Shipping' => build_change_order_status_btns($id, $user_dept_code, $job_number, $enterprise, $order_statuses[ $id ])[8],
		);


	}

	// Remove job number keys
	$json = array_values($json);

	//encode for JSON and output to screen
	print(json_encode($json));

}
//failed to execute SQL transaction
catch (PDOException $e) {
	print $e->getMessage();
}

function build_change_order_status_btns($id, $user_dept_code, $job_number, $enterprise, $status) {
	
	// define output button array
	$btn = [];

	// produce the buttons
	foreach ( $status as $dept => $stat ) {
		// enabled if user dept is 1,2,3 or the current dept matches the user's dept
		$enabled = in_array( $user_dept_code, [ 1, 2, 3 ] ) || in_array( $dept, explode( ',', $user_dept_code ) ) ? '' : ' disabled';

		// populate the dynamic values. you should actually use a template here with replaceable tags, then only produce the button that matches the current status value
		$buttons[ 1 ] = "<button type='button' class='btn btn-warning btn-sm btn_change_order_status_dialog' data-order-id='$id' data-order-number='$job_number' data-order-enterprise='$enterprise' data-dept-code='$dept'$enabled>In Progress</button>";
		$buttons[ 2 ] = "<button type='button' class='btn btn-danger btn-sm btn_change_order_status_dialog' data-order-id='$id' data-order-number='$job_number' data-order-enterprise='$enterprise' data-dept-code='$dept'$enabled>Delayed</button>";
		$buttons[ 3 ] = "<button type='button' class='btn-success btn-sm btn_change_order_status_dialog' data-order-id='$id' data-order-number='$job_number' data-order-enterprise='$enterprise' data-dept-code='$dept'$enabled>Finished</button>";
		$buttons[ 0 ] = "<button type='button' class='btn btn-secondary btn-sm btn_change_order_status_dialog' data-order-id='$id' data-order-number='$job_number' data-order-enterprise='$enterprise' data-dept-code='$dept'$enabled>Not Started</button>";

		// get the button that matches the current status value for each dept
		$btn[ $dept ] = $buttons[ $stat ];
	}
	// examine the results
	return $btn;
}
Sponsor our Newsletter | Privacy Policy | Terms of Service