Speeding up PHP foreach loop with unset()?

1.2k views Asked by At

Based on what I have read about the internals of php arrays this may not be possible, but I wanted to run this past you and see if there's a chance...

I am pulling two results sets from a SQL query. One is an array of customers (an array of arrays, actually - with each customer having and ID and some other personal data), and the second array is an array of customer orders (also an array of arrays). Basically my foreach loop is matching the customer ID values from the customer array with all of the orders that customer made in the second array and pushing them into a new third data structure.

So let's say I make my SQL query and I pull an array of 500 customers and 3,000 orders. On average then, one customer will have six orders to match. For each iteration through the customer array I need to also iterate through the entire orders array to get all the matches. Then I will push these into a different data structure which is ultimately what I will use.

I wanted to know if unsetting the matched rows from both of the original arrays would speed up the foreach loop since it would in principle have less to iterate over with each cycle. Based on how PHP uses hashes and buckets for its arrays, and the way it makes a copy of arrays in foreach loops, I am wondering if a performance increase would actually occur. I plan to test this with some dummy data but I wanted to know if anyone here has run across a similar situation.

Thanks!!

EDIT - thanks for your answers. Yes, joining the tables is probably the best way, but I am asking this question to gain a better understanding of how PHP handles arrays, etc.

I wrote a test script and I can now see that using unset() doesn't help me:

$customers = Array('1' =>'Jim', '2' => 'Bill', '3' => 'John', '4' => 'Ed', '5' => 'Greg');
$orders = Array();
$final = Array();

for ($x = 0; $x < 1000000; $x++) {
    $orders[$x] = rand(1,5);
}

$start = microtime(true);
$counter = 0;
foreach ($customers as $key=>$customer) {
    $final[$customer] = Array();
    foreach ($orders as $key=>$order) {
        $counter++; 
        if ($order == $key) {
            $final[$customer][] = $order;
            unset($orders[$key]);               
        }
    }
}
echo $counter; // I usually get the same number of iterations whether unset() is used or not

$finish = microtime(true) - $start; // similar or worse performance if unset() is used

What I see is no performance increase with unset(), but rather a decrease. On top of that, unset() doesn't actually remove the row from the array. When I do a count() of the $orders array it is the same at the end as it is at the beginning.

2

There are 2 answers

0
Satish On

As per my under standing you are getting results of Customers separately and orders data separately from DB.

Customer

ID     Name     Add..

1     one     ...

2     two     ...

3     three     ....

Orders

ID     CID     ord

1     1     ...

2     3     ....

3     3     ....

4     2     ....

While retrieving data itself Join the Tables and get the required results, for example..

SELECT c.Name, c.ID, o.ord FROM customer c LEFT JOIN orders o ON c.ID = o.CID;

You can add where condition as per requirement;

0
zaf On

This is just off the top of my head:

Appending data on to another array using the 'arrayxyz[]' syntax could be faster than 'unset' due to the overhead of logic that needs to run to keep the 'foreach' in a useful state.

Also, unsetting an array item removes the key/value, and if you are using numeric indexes then this leaves a 'hole' which may or may not affect the 'count' function.

You may need to use 'array_values' to reindex the array.