Magento: самый быстрый способ обновить атрибут продукта

15

Я ищу самый быстрый и надежный способ массового обновления атрибутов. Ниже приведены методы, которые мне известны, но я не знаю, с какими из них я должен идти.

$store_id = 0;
Mage::getSingleton('catalog/product_action')->updateAttributes(
    array($product_id),
    array('attribute_code' => $attribute_code),
    $store_id
);

или

$product->setData($attribute_code, 1234); 
$product->getResource()->saveAttribute($product, $attribute_code); 
Дипак Малла
источник

Ответы:

31

Самый быстрый способ - делать прямые выборки и вставки / обновления в базе данных, но это не самый безопасный. Вы можете легко сломать вещи.

Я использую Mage::getSingleton('catalog/product_action')->updateAttributes(...)подход.
Это быстро, вы можете использовать его для массового обновления атрибутов продукта, вы можете обновить значение атрибута для конкретного магазина.
Я думаю, что это покрывает большинство необходимых случаев.

Мариус
источник
спасибо, Мариус, я ожидал твоего ответа, кстати, твой главный создатель модуля - Кул
Дипак Малла
1
это не самый быстрый выбор ... проверьте мой ответ ниже
Fra
@Fra Как твой метод быстрее? Это вовлекает load. что угодно, но не быстро. Например, в методе 2 первая строка с загрузкой продукта является бесполезной. Вы не используете $productнигде.
Мариус
@Fra. Когда вы отрицаете чей-то ответ, хорошо бы указать причину. Что не так с моим ответом?
Мариус
1
Я мог бы сказать то же самое для вашего ответа ... это не самый быстрый способ. прямые запросы SQL - самый быстрый способ. Я не думаю, что ваша причина достаточно для подавления. Но вы имеете право на свое мнение.
Мариус
27

На самом деле есть 3 способа обновить атрибут продукта без сохранения всего продукта. В зависимости от кода / требований одно может быть быстрее другого.

Способ 1:

$product = Mage::getModel('catalog/product')->load($product_id);
$resource = $product->getResource();

$product->setData($attribue_code, $value);
$resource->saveAttribute($product, $attribute_code);

Способ 2:

$updater = Mage::getSingleton('catalog/product_action');
$updater->updateAttributes(array($product_id), array( $attribute_code => $value), 0);

Способ 3: (самый быстрый)

 $update_resource = Mage::getResourceSingleton('catalog/product_action');
 $update_resource->updateAttributes(array($product_id), array( $attribute_code => $value), 0);

Все вышеперечисленные методы намного быстрее, что сохраняет весь продукт в любом случае, есть некоторые существенные различия в производительности:

Method 1:

  • является самым быстрым, но требуется для загрузки продукта.
  • не вызывает событие переиндексации (поэтому быстрее)
  • это работает во внешнем интерфейсе

Method 2:

  • позволяет массово обновлять продукт
    (вы можете передать несколько продуктов и несколько атрибутов)
  • это вызывает событие массового действия и относительный зависимый переиндекс
  • это не работает во внешнем интерфейсе

Method 3:

  • он похож на метод 2, но не вызывает никакого другого наблюдателя / индексатора
    (поэтому это смешанный подход между методом 1 и 2)

Метод 3 является более гибким, в любом случае вам придется переиндексировать этот продукт / атрибуты вручную. (чтобы они обновлялись во внешнем интерфейсе).
Это может быть полезно, если вы хотите быстро обновить множество продуктов, а затем вызвать в конце реиндекс.
(если вы используете метод 2, после обновления вызывается переиндексация для каждого продукта, и эти многочисленные вызовы замедляют весь процесс)

Чтобы вручную переиндексировать отдельный продукт, см. Функции, предоставляемые Mage_Catalog_Model_Product_Flat_Indexer, такие как:

  • updateAttribute($attributeCode, $store = null, $productIds = null)
  • updateProduct($productIds, $store = null)
  • ...
От
источник
4
всегда было бы лучше прокомментировать downvote ...
Fra
Просто небольшая заметка, значение $ должно быть кодом значения (целое число), а не «текстовым» значением, которое вы видите в своем интерфейсе
Ali Alwash
хммм интересно. Метод 2 звучит великолепно, только у вас нет контроля над «обратной связью», что получилось, а что нет? Способ 1 тоже хорош. Но когда я закончу обновлять данные в цикле: могу ли я вручную запустить реиндекс, возможно, чтобы решить эту проблему для отдельных идентификаторов продуктов?
snh_nl
Странный. используя метод 2. Я получаю сообщение об ошибке неизвестного фильтра по столбцу `` `Поступило исключение: SQLSTATE [42S22]: Столбец не найден: 1054 Неизвестный столбец 'catalog_product_entity.value_id' в 'списке полей', запрос был: SELECT catalog_product_entity. value_idОТ catalog_product_entityГДЕ (entity_type_id = 4 AND attribute_id = '68 'И entity_id = '29') `` `не ожидал этого. Запуск на 1.9.3.2
snh_nl
1
Спасло меня часы работы.
dipole_moment
3

Обновить

Я ищу самый быстрый и надежный способ массового обновления атрибутов

«Массовое обновление атрибутов» для атрибутов или продуктов?

Думаю, что обновление нескольких атрибутов уже отвечено, но для продуктов это может быть полезно ...

Если вы хотите обновить продукты из коллекции, вы не должны делать это ...

foreach ($collection as $product) {
    $product->setSomeData(...);
    # not here
    $product->save();
}

Это будет отправлять события, перестраивать цены и индексы. С этим никакие события (и некоторые другие вещи) не пропускаются и намного быстрее.

foreach ($collection as $product) {
    $product->setSomeData(...);
}
$collection->save();

Чтобы избежать ценовых обновлений, вы можете добавить ...

$product->setIsMassupdate(true);

Чтобы отключить / включить переиндексацию на лету, взгляните на это ... https://github.com/Flagbit/Magento-ChangeAttributeSet/commit/676f3af77fec880bc64333403675d183e8639fae

/**
 * Set indexer modes to manual
 */
private function _storeRealtimeIndexer()
{
    $collection = Mage::getSingleton('index/indexer')->getProcessesCollection();
    foreach ($collection as $process) {
        if($process->getMode() != Mage_Index_Model_Process::MODE_MANUAL){
            $this->_index[] = $process->getIndexerCode();
            $process->setData('mode', Mage_Index_Model_Process::MODE_MANUAL)->save();
        }
    }

}
/**
 * Restore indexer modes to realtime an reindex product data
 */
private function _restoreRealtimeIndexer()
{
    $reindexCodes = array(
        'catalog_product_attribute',
        'catalog_product_flat'
    );
    $indexer = Mage::getSingleton('index/indexer');
    foreach ($this->_index as $code) {
        $process = $indexer->getProcessByCode($code);
        if (in_array($code, $reindexCodes)) {
            $process->reindexAll();
        }
        $process->setData('mode', Mage_Index_Model_Process::MODE_REAL_TIME)->save();
    }
}

А также очистка кеша перед массовым обновлением может повысить производительность ...

Mage::app()->getCacheInstance()->flush();

Некоторые цифры отладки здесь: https://github.com/Flagbit/Magento-ChangeAttributeSet/issues/16


Mage::getSingleton('catalog/product_action')->updateAttributes(...) кажется, не самый быстрый способ ... по крайней мере, не с настройкой mutlistore и плоскими таблицами ...

  • saveAttribute()

    $product = Mage::getModel('catalog/product')->load($productId);
    $resource = $product->getResource();
    $product->setData($attributeCode, $attributeValue);
    $resource->saveAttribute($product, $attributeCode);
    • Всего вкл. Время стены (мкс): 437 787 мксек
    • Всего вкл. ЦП (микросекунд): 423 600 микросекунд
    • Всего вкл. MemUse (байты): 4 433 848 байтов
    • Всего вкл. PeakMemUse (байты): 4,395,128 байтов
    • Количество функциональных вызовов: 25 711
  • updateAttributes()

    Mage::getSingleton('catalog/product_action')->updateAttributes(
        array($productId),
        array($attributeCode => $attributeValue),
        $storeId
    );
    • Всего вкл. Время стены (мксек): 3 676 950 мксек
    • Всего вкл. ЦП (микросекунд): 3 122 064 микросекунд
    • Всего вкл. MemUse (байты): 8,174,792 байта
    • Всего вкл. PeakMemUse (байты): 8 199 192 байта
    • Количество функциональных вызовов: 150 132
  • updateAttributes() (ресурс синглтон)

    Mage::getResourceSingleton('catalog/product_action')->updateAttributes(
        array($productId),
        array( $attributeCode => $attributeValue),
        $storeId
    );
    • Всего вкл. Время стены (мкс): 94 155 мкс
    • Всего вкл. ЦП (микросекунд): 48 568 микросекунд
    • Всего вкл. MemUse (байты): 1 426 304 байта
    • Всего вкл. PeakMemUse (байты): 1 370 456 байтов
    • Количество функциональных вызовов: 2221
sv3n
источник
Вы можете просмотреть мой ответ, чтобы понять, почему эта функция занимает разное время ...
Фра
Для выпадающих данных updateAttributes() (resource singleton)принимает фактическое значение администратора? или идентификатор выпадающего элемента? (каким-то образом мы всегда не получаем значение / пустое значение, используя этот метод, т.е. ничего не выбрано
snh_nl
@snh_nl вы должны использовать ID - запятую для атрибутов множественного выбора.
sv3n