1

I'm writing a script to update product weight programmatically in magento 1.9.x. The file contains more than ~50000

When I start script the execution time for 100 records is 20 seconds, then the execution time happen very slow, 1 second for item.

Why the first execution set of 100 items is fast, but next sets are very slow? Do you have any Idea, how can I fix this issue?

require_once $mageFilename;
ini_set('display_errors', 1);
umask(0);
Mage::app('admin');
Mage::register('isSecureArea', 1);
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

/***************** UTILITY FUNCTIONS ********************/

function show_status($done, $total, $size=30)
{
    static $start_time;

    // if we go over our bound, just ignore it
    if($done > $total) return;

    if(empty($start_time)) $start_time=time();
    $now = time();

    $perc=(double)($done/$total);

    $bar=floor($perc*$size);

    $status_bar="\r[";
    $status_bar.=str_repeat("=", $bar);
    if($bar<$size){
        $status_bar.=">";
        $status_bar.=str_repeat(" ", $size-$bar);
    } else {
        $status_bar.="=";
    }

    $disp=number_format($perc*100, 0);

    $status_bar.="] $disp%  $done/$total";

    $rate = ($now-$start_time)/$done;
    $left = $total - $done;
    $eta = round($rate * $left, 2);

    $elapsed = $now - $start_time;

    $status_bar.= " remaining: ".number_format($eta)." sec.  elapsed: ".number_format($elapsed)." sec.";

    echo "$status_bar  ";

    flush();

    // when done, send a newline
    if($done == $total) {
        echo "\n";
    }
}

function _getConnection($type = 'core_read')
{
    return Mage::getSingleton('core/resource')->getConnection($type);
}

function _getTableName($tableName)
{
    return Mage::getSingleton('core/resource')->getTableName($tableName);
}

function _checkIfSkuExists($sku)
{
    $connection = _getConnection('core_read');
    $sql        = "SELECT COUNT(*) AS count_no FROM " . _getTableName('catalog_product_entity') . " WHERE sku = ?";
    $count      = $connection->fetchOne($sql, array($sku));
    if($count > 0){
        return true;
    }else{
        return false;
    }
}

function _getIdFromSku($sku)
{
    $connection = _getConnection('core_read');
    $sql        = "SELECT entity_id FROM " . _getTableName('catalog_product_entity') . " WHERE sku = ?";
    return $connection->fetchOne($sql, array($sku));
}



$csv                = new Varien_File_Csv();
$data               = $csv->getData('weight.csv'); //path to csv
array_shift($data);
$message = '';
$count   = 1;
$total = count($data);
$data_chunk = array_chunk($data, 100);

foreach($data_chunk as $data_c){
    foreach($data_c as $_data){
        if(_checkIfSkuExists($_data[0])){
            try{
                $product = Mage::getModel('catalog/product')->load(_getIdFromSku($_data[0]));
                if(isset($_data[1])){
                    $weight = $_data[1];
                    $product->setWeight($weight);
                    $product->save();
                }
                $message .=  $count .'>Weight for Sku (' . $_data[0] . ')' . "\n";
            }catch(Exception $e){
                $message .=  $count .'> <b style="color:red">Error</b>:: While Upating Weight to (' . $_data[1] . ') of Sku (' . $_data[0] . ') => '.$e->getMessage() . "\n";
            }
        }else{
            $message .=  $count .'> <b style="color:red">Error</b>:: Product Model (' . $_data[0] . ') does\'t exist.' . "\n";
        }
        $count++;
        show_status($count, $total, $size=30);
    }
    sleep(1);
    unset($data_c);
}

weight.csv

sku,weight
item_1,16.40
item_2,22.50
........
1
  • Has this worked for 50k products?
    – sv3n
    Mar 3, 2018 at 3:22

2 Answers 2

1

I guess the biggest problems are that you use product = Mage::getModel('catalog/product')->load() and $product->save() inside a foreach loop.

You can try something like this (not tested on 50k products!)

$csv = new Varien_File_Csv();
$data = $csv->getDataPairs('weight.csv', 0, 1); # instead of getData()
unset($data['sku']); # unset header row

$products = Mage::getModel('catalog/product')->getCollection()
    ->addAttributeToFilter('sku', array('in' => array_keys($data)));

foreach ($products as $product) {
    $product->setWeight($data[$product->getSku()]);
    $product->getResource()->saveAttribute($product, 'weight');
}
1

The reason behind the load is might be indexing which getting called on save of each product. So first of all you should change the indexing mode to "Manual update" for all the index before running the script.

Other thing is that if you want to update specific attribute then you can do it by following snippet:

$product = Mage::getModel('catalog/product')->loadByAttribute('sku', PRODUCT_SKU);
if ($product) {
  $productId = $product->getId();
  Mage::getSingleton('catalog/product_action')->updateAttributes(array($productId),array('weight'=>PRODUCT_WEIGHT),STORE_ID);
}

Please replace the PRODUCT_SKU,PRODUCT_WEIGHT,STORE_ID with appropriate value.

I hope this will help you.

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.