Categories


Archives


Recent Posts


Categories


Magento’s getLastItem Method Considered Harmful

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

Every model in Magento has an “array like” collection object.

$collection = Mage::getModel('sales/order')->getCollection();
foreach($collection as $order)
{
    echo $order->getIncrementId();
}

Each collection also has a convenience method to grab the first or the last item from the collection

$item = $collection->getFirstItem();
$item = $collection->getLastItem();

This week a client of mine called me frantically because their checkout page was crashing. After some quick log sweeping I discovered PHP was bailing because the memory_limit of 256 MB had been reached. We quickly upped the limit to 512 MB for the saveOrder action, and orders continued to flow through. Problem solved!

Well, almost solved. I put some basic monitoring in place, and noticed the memory use on the saveOrder method was increasing with each order. This meant we had a few weeks before the limit of 512 MB was reached. Not good.

After some memory profiling using xDebug, I found the following bit of custom code (from a long gone offshore shop) firing during the checkout page request.

$orderid = Mage::getModel('sales/order')->getCollection()->getLastItem()->getIncrementId();

On the surface, it seems harmless, and during testing it never triggered a single bug. However, as the number of orders in the system increased, this innocuous call ended up consuming silly amounts of memory. To fix the problem, we added a sort to the collection’s query, and limited it to a single item.

$orders = Mage::getModel('sales/order')->getCollection();
$orders->getSelect()->order('entity_id DESC')->limit('1');
$orderid = $orders->getLastItem()->getIncrementId();

This preserved the exact behavior of the previous code, but did so without each successful order costing a quarter gig of memory.

The long and the short of it: Don’t use getLastItem with collections that will grow over time, especially in code that fires during a mission critical process.

Copyright © Alan Storm 1975 – 2017 All Rights Reserved

Originally Posted: 15th March 2012