4

I need to load one attribute value(weight) for many product IDs.

Say list of the product ids is in array $productIDs.

In general case, which approach is faster,

  1. Loading raw attribute value for each product, without loading products:

    foreach ($productIds as $productId) {
        $weight[$productId] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($productId, 'weight', $store_id );
    }
    
  2. Using collection:

    $collection = Mage::getModel('catalog/product')->getCollection()->addAttributeToFilter('id', array('in' => $productIds));
    foreach ($collection as $product) {
        $weight[$product->getId()] = $product->getWeight();
    }
    

3 Answers 3

4

Well you can test is easily, create the following test.php file in your root folder:

<?php
//some settings
error_reporting(E_ALL | E_STRICT);
define('MAGENTO_ROOT', getcwd());
$mageFilename = MAGENTO_ROOT . '/app/Mage.php';
require_once $mageFilename;
Mage::setIsDeveloperMode(true);
ini_set('display_errors', 1);
umask(0);
//instantiate the app model
Mage::app();

$productIds = array();
$storeId = 1;
$weight1 = array();
$weight2 = array();

Varien_Profiler::enable();
Varien_Profiler::start("getattributerawvalue");
foreach ($productIds as $productId) {
    $weight1[] = Mage::getResourceModel('catalog/product')->getAttributeRawValue($productId, 'weight', $storeId);
}
Varien_Profiler::stop("getattributerawvalue");
Varien_Profiler::start("collection");
$collection = Mage::getModel('catalog/product')->getCollection()->addAttributeToFilter('id', array('in' => $productIds));
foreach ($collection as $product) {
    $weight2[$product->getId()] = $product->getWeight();
}
Varien_Profiler::stop("collection");

$timers = Varien_Profiler::getTimers();

#$out = '<div style="position:fixed;bottom:5px;right:5px;opacity:.1;background:white" onmouseover="this.style.opacity=1" onmouseout="this.style.opacity=.1">';
#$out = '<div style="opacity:.1" onmouseover="this.style.opacity=1" onmouseout="this.style.opacity=.1">';
$out = "<a href=\"javascript:void(0)\" onclick=\"$('profiler_section').style.display=$('profiler_section').style.display==''?'none':''\">[profiler]</a>";
$out .= '<div id="profiler_section" style="background:white; display:block">';
$out .= '<pre>Memory usage: real: '.memory_get_usage(true).', emalloc: '.memory_get_usage().'</pre>';
$out .= '<table border="1" cellspacing="0" cellpadding="2" style="width:auto">';
$out .= '<tr><th>Code Profiler</th><th>Time</th><th>Cnt</th><th>Emalloc</th><th>RealMem</th></tr>';
foreach ($timers as $name=>$timer) {
    $sum = Varien_Profiler::fetch($name,'sum');
    $count = Varien_Profiler::fetch($name,'count');
    $realmem = Varien_Profiler::fetch($name,'realmem');
    $emalloc = Varien_Profiler::fetch($name,'emalloc');
    if ($sum<.0010 && $count<10 && $emalloc<10000) {
        continue;
    }
    $out .= '<tr>'
        .'<td align="left">'.$name.'</td>'
        .'<td>'.number_format($sum,4).'</td>'
        .'<td align="right">'.$count.'</td>'
        .'<td align="right">'.number_format($emalloc).'</td>'
        .'<td align="right">'.number_format($realmem).'</td>'
        .'</tr>'
    ;
}
$out .= '</table>';
$out .= '<pre>';
$out .= print_r(Varien_Profiler::getSqlProfiler(Mage::getSingleton('core/resource')->getConnection('core_write')), 1);
$out .= '</pre>';
$out .= '</div>';
echo $out;

Replace the following two variables with the ones you want to use:

$productIds = array();
$storeId = 1;

Now access the file via a browser and see the results.

I tested on my side with 50 products:

  • Using getAttributeRawValue : Time : 0.0939 seconds / Emalloc: 1,610,440
  • Using collection : Time: 0.7858 seconds / Emalloc: 9,195,992

So the first method is almost 10 times faster and almost uses 10 times less memory.

1
  • 1
    That is fantastic and a timer to boot!
    – SR_Magento
    Commented Dec 1, 2016 at 10:38
3

Bit different numbers here. "xhprof'ed" with with ~700 products ....

$storeId = 1;
$productIds = Mage::getModel('catalog/category')->load(41)
    ->getProductCollection()
    ->getAllIds();

Xhprof_Profiler::start();
# ...
var_dump($weight);
Xhprof_Profiler::stop();

1) getAttributeRawValue()

$rm = Mage::getResourceModel('catalog/product');
foreach ($productIds as $productId) {
    $weight[$productId] = $rm->getAttributeRawValue($productId, 'weight', $storeId);
}
  • Total Incl. Wall Time (microsec): 5,572,944 microsecs
  • Total Incl. CPU (microsecs): 5,425,659 microsecs
  • Total Incl. MemUse (bytes): 1,302,512 bytes
  • Total Incl. PeakMemUse (bytes): 1,272,360 bytes
  • Number of Function Calls: 254,235

2) Mage::getModel('catalog/product')->getCollection()

$collection = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToSelect('weight')
    ->addAttributeToFilter('entity_id', $productIds);

foreach ($collection as $product) {
    $weight[$product->getId()] = $product->getWeight();
}
  • Total Incl. Wall Time (microsec): 2,588,250 microsecs
  • Total Incl. CPU (microsecs): 2,549,021 microsecs
  • Total Incl. MemUse (bytes): 3,717,824 bytes
  • Total Incl. PeakMemUse (bytes): 3,834,616 bytes
  • Number of Function Calls: 124,602

3) Mage::getResourceModel('catalog/product_collection')

$collection = Mage::getResourceModel('catalog/product_collection')
    ->addAttributeToSelect('weight')
    ->addAttributeToFilter('entity_id', $productIds);

foreach ($collection as $product) {
    $weight[$product->getId()] = $product->getWeight();
}
  • Total Incl. Wall Time (microsec): 2,603,804 microsecs
  • Total Incl. CPU (microsecs): 2,584,472 microsecs
  • Total Incl. MemUse (bytes): 3,706,600 bytes
  • Total Incl. PeakMemUse (bytes): 3,821,336 bytes
  • Number of Function Calls: 124,554

5) using addIdFilter() *

$collection = Mage::getResourceModel('catalog/product_collection')
    ->addAttributeToSelect('weight')
    ->addIdFilter($productIds);

foreach ($collection as $product) {
    $weight[$product->getId()] = $product->getWeight();
}
  • Total Incl. Wall Time (microsec): 2,439,878 microsecs
  • Total Incl. CPU (microsecs): 2,419,062 microsecs
  • Total Incl. MemUse (bytes): 3,689,440 bytes
  • Total Incl. PeakMemUse (bytes): 3,700,200 bytes
  • Number of Function Calls: 118,409

6) using getColumnValues() *

$collection = Mage::getResourceModel('catalog/product_collection')
    ->addAttributeToSelect('weight')
    ->addIdFilter($productIds);

$weight = array_combine(
    $collection->getColumnValues('entity_id'),
    $collection->getColumnValues('weight')
);
  • Total Incl. Wall Time (microsec): 2,140,222 microsecs
  • Total Incl. CPU (microsecs): 2,119,635 microsecs
  • Total Incl. MemUse (bytes): 3,180,560 bytes
  • Total Incl. PeakMemUse (bytes): 3,260,200 bytes
  • Number of Function Calls: 104,722

* nearly same result for 'entity_id', array('in' => $productIds), but it's less to type and better readable

1
  • Great job ! +1 :)
    – PЯINCƎ
    Commented Jun 14, 2017 at 0:10
0

In my opinion Mage::getResourceModel('catalog/product')->getAttributeRawValue($productId, 'weight', $store_id );

Is faster because here you go to that product and fetch a single attribute value only.


In other case you load collection(though its one product) and again in another call you get the value and also here you load all unnecessary data.

4
  • You first explanation is wrong. The first one returns a resource model whereas the second returns a collection model Commented Dec 1, 2016 at 10:32
  • @RaphaelatDigitalPianism stackoverflow.com/questions/21153973/… please see the answer Commented Dec 1, 2016 at 10:39
  • Yes this SO answer is totally right, your answer is wrong. The right answer is Mage::getResourceModel('catalog/product_collection') returns the same thing as Mage::getModel('catalog/product')->getCollection() which is not what you're saying Commented Dec 1, 2016 at 10:42
  • @RaphaelatDigitalPianism I will update my answer Commented Dec 1, 2016 at 10:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.