В настоящее время я пытаюсь улучшить пару модулей в отношении производительности.
Некоторые из вас могут знать, как использовать walk()
метод сбора, который очень полезен, чтобы не зацикливаться на товарах напрямую.
Кроме того, благодаря @Vinai можно также использовать delete()
метод сбора данных .
Но я заметил, что собственные файлы Magento 1 не всегда используют любой из этих методов для удаления.
Один из худших кодов, который я видел, - это massDelete()
метод, из app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php
которого продукты загружаются в цикл перед удалением .
foreach ($productIds as $productId) {
$product = Mage::getSingleton('catalog/product')->load($productId);
Mage::dispatchEvent('catalog_controller_product_delete', array('product' => $product));
$product->delete();
}
Поэтому я провел несколько тестов производительности, добавил несколько вызовов в журналы, чтобы проверить время и использование памяти для удаления 100 продуктов.
Тест 1: walk
метод
Я заменил оригинальный код, вставленный выше, этим кодом:
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('entity_id')
->addIdFilter($productIds)
->walk('delete');
И мои результаты следующие на моем crappy dev сервере (в среднем по 10 тестам):
- Исходный код: 19,97 секунд, использовано 15,84 МБ
- Пользовательский код: 17,12 секунд, используется 15,45 МБ
Таким образом, для удаления 100 продуктов мой пользовательский код на 3 секунды быстрее и использует на 0,4 МБ меньше.
Тест 2: Использование delete()
метода сбора
Я заменил оригинальный код на этот:
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('entity_id')
->addIdFilter($productIds)
->delete();
И умопомрачительные вот результаты:
- Исходный код: 19,97 секунд, использовано 15,84 МБ
- Пользовательский код: 1,24 секунды, 6,34 МБ используется
Поэтому при удалении 100 продуктов мой пользовательский код работает на 18 секунд быстрее и использует меньше 9 МБ.
Как указано в комментариях, похоже, что этот метод не вызывает события Magento (после загрузки, после удаления) и очистки индекса / кэша.
Вопрос
Итак, мой вопрос: есть ли причина, по которой основная команда Magento не использовала метод walk('delete')
или событие лучше, чем delete()
метод сбора вместо загрузки продуктов в цикле (что, как мы все знаем, очень и очень плохая практика)?
Главная цель - знать о таких ключевых моментах в случае разработки модуля: есть ли конкретные случаи, когда нельзя использовать метод walk
/ collection delete()
?
РЕДАКТИРОВАТЬ: причина определенно не в том, что catalog_controller_product_delete
событие отправляется, поскольку один и тот же код можно найти в нескольких местах (проверьте massDelete
методы) в ядре Magento. Я использовал пример продуктов, чтобы подчеркнуть производительность, поскольку они, как правило, являются крупнейшими организациями
источник
getSingleton()
качестве показателя производительности вместо очевидного использования коллекции. Да, и событие можно вызвать с помощью коллекции, но не с помощьюwalk()
ярлыка.delete()
делает запрос DELETE вместо загрузки коллекции и удаления каждого продукта. С этим вы действительно потеряете события.Ответы:
Примечание, но вы должны посмотреть на использование Varien Profiler для этого!
Хотя я не сомневаюсь, что ваши изменения повысят производительность, было бы полезно предоставить результаты «до» для сравнения улучшений.
Ну, мы знаем из других вопросов на этом форуме следующее:
Поэтому я хотел бы предположить, что пример, который вы нашли, вероятно, является одним из потенциально многих драгоценных камней, скрытых в коде, который был написан давным-давно и / или менее опытным разработчиком. Как и большая часть основного кода (и кода сообщества!), Он был бы протестирован на небольшом наборе данных и не проверен в бою, поэтому производительность, возможно, не отслеживалась.
Является ли ваше улучшение полезным и более тесно связано с лучшими практиками, чем исходный код? Да. Однако вы, как разработчик сообщества Magento [1.x], не можете вносить предлагаемые улучшения, как вы делаете это с Magento 2, поэтому я бы предложил реализовать это в локальном модуле, если вам это требуется для производительности в одном из ваших магазинов. или не обращайте на это внимания, если это не влияет на вас, но вы заметили это во время исследования.
Как обновление вашего вопроса редактирования, я уверен, что вы знаете, что метод ходьбы в Varien_Data_Collection принимает произвольный обратный вызов, так что вы можете использовать его для всего, что вы, вероятно, хотели. Для отправки события в исходном примере вы можете сделать это с помощью функции ходьбы, а также удаления.
Единственная причина, по которой я мог представить, что загрузка продукта перед его удалением будет полезной, может заключаться в том, что наблюдателям, прикрепленным к этому событию, может понадобиться полный набор данных, недоступный без предварительной загрузки продукта. Если это так, то это объясняет, почему они используют синглтон, а не модель, чтобы, по крайней мере, минимизировать накладные расходы объекта.
источник
Я думаю, что они делают это, чтобы запустить
catalog_controller_product_delete
событие, которое используется Mage_Tag.catalog_product_delete_before
илиcatalog_product_delete_after
будет означать, что это не нужно, хотя я бы подумал. Интересно, это конкретное событие также используется для регистрации действий администратора.источник
massDelete()
действиемCustomerController.php
Я думаю, что массовое удаление должно работать как удаление одного (полностью загруженного) продукта.
Ибо
$collection->delete()
ответ уже дан. Если вы не активируетеdeleter_before
,delete_after
я мог бы сломать некоторые расширения и обойти некоторых наблюдателей, используемых в ядре.$collection->walk('delete')
возможно, сработает, но все же имеет тот недостаток, что данные о продукте не полны. Это также может нарушить работу пользовательских наблюдателей, если они полагаются на дополнительные данные, например, на объект товарной позиции.Я думаю, если вы измените
->addAttributeToSelect('entity_id')
к->addAttributeToSelect('*')
и добавить->setFlag('require_stock_items', true)
(добавить данные о запасах в продукты) не будет работать лучше , чем «петля удаления».Выглядит как плохой стиль, но я думаю, что это правильно для обоих действий массового удаления.
Я использую
walk()
иdelete()
для пользовательских моделей тоже, но я знаю, что нет наблюдателей илиentity_id
достаточно. Просто чтобы упомянуть,walk()
будет работать со всеми событиями, используемыми в ядре, потому что они только используют$product->getId()
, но вы не знаете о сторонних наблюдателей.источник