Ich versuche derzeit, einige Module hinsichtlich der Leistung zu verbessern.
Einige von Ihnen kennen möglicherweise die Verwendung der walk()
Erfassungsmethode, die sehr nützlich ist, um ein direktes Durchlaufen von Produkten zu vermeiden.
Darüber hinaus und dank @Vinai kann man auch die Erfassungsmethode delete()
verwenden.
Ich habe jedoch festgestellt, dass native Magento 1-Dateien nicht immer eine dieser Methoden zum Löschen verwenden.
Einer der schlimmsten Codes, die ich je gesehen habe, ist die massDelete()
Methode, app/code/core/Mage/Adminhtml/controllers/Catalog/ProductController.php
mit der Produkte vor dem Löschen in eine Schleife geladen werden .
foreach ($productIds as $productId) {
$product = Mage::getSingleton('catalog/product')->load($productId);
Mage::dispatchEvent('catalog_controller_product_delete', array('product' => $product));
$product->delete();
}
Also habe ich einige Leistungstests durchgeführt und einige Protokollierungsaufrufe hinzugefügt, um die benötigte Zeit und die Speichernutzung für das Löschen von 100 Produkten zu überprüfen.
Test 1: walk
Methode
Ich habe den oben eingefügten Originalcode durch diesen Code ersetzt:
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('entity_id')
->addIdFilter($productIds)
->walk('delete');
Und meine Ergebnisse sind die folgenden auf meinem beschissenen Entwicklungsserver (Durchschnitt basierend auf 10 Tests):
- Originalcode: 19,97 Sekunden, 15,84 MB verwendet
- Benutzerdefinierter Code: 17,12 Sekunden, 15,45 MB verwendet
Beim Löschen von 100 Produkten ist mein benutzerdefinierter Code 3 Sekunden schneller und verbraucht 0,4 MB weniger.
Test 2: die Sammlung verwendet delete()
Methode
Ich habe den Originalcode durch diesen ersetzt:
$collection = Mage::getResourceModel('catalog/product_collection')
->addAttributeToSelect('entity_id')
->addIdFilter($productIds)
->delete();
Und umwerfend sind hier die Ergebnisse:
- Originalcode: 19,97 Sekunden, 15,84 MB verwendet
- Benutzerdefinierter Code: 1,24 Sekunden, 6,34 MB verwendet
Beim Löschen von 100 Produkten ist mein benutzerdefinierter Code 18 Sekunden schneller und verbraucht 9 MB weniger.
Wie in den Kommentaren angegeben, scheint diese Methode weder die Magento-Ereignisse (nach dem Laden, nach dem Löschen) noch den Index- / Cache-Flush auszulösen.
Frage
Meine Frage lautet also: Gibt es einen Grund, warum das Magento-Kernteam walk('delete')
die Erfassungsmethode oder das Ereignis nicht besser delete()
verwendet hat, anstatt Produkte in einer Schleife zu laden (von der wir alle wissen, dass sie eine sehr, sehr schlechte Praxis ist)?
Hauptziel ist es, solche Schlüsselpunkte im Falle einer Modulentwicklung zu kennen: Gibt es bestimmte Fälle, in denen man die walk
/ collection- delete()
Methode nicht verwenden kann ?
BEARBEITEN: Der Grund liegt definitiv nicht darin, dass das catalog_controller_product_delete
Ereignis ausgelöst wird, da derselbe Code an mehreren Stellen (überprüfen Sie die massDelete
Methoden) im Magento-Kern gefunden werden kann. Ich habe das Beispiel von Produkten verwendet, um die Leistung hervorzuheben, da es sich normalerweise um die größten Einheiten handelt
quelle
getSingleton()
als Leistungsmaß anstelle der offensichtlichen Verwendung der Sammlung. Oh, und es ist möglich, das Ereignis auch mit einer Sammlung auszulösen, nur nicht mit derwalk()
Verknüpfung.delete()
führt eine DELETE-Abfrage durch, anstatt die Sammlung zu laden und jedes Produkt zu löschen. Mit diesem verlieren Sie wirklich die Ereignisse.Antworten:
Randnotiz, aber Sie sollten sich die Verwendung des Varien Profiler dafür ansehen!
Ich bezweifle zwar nicht, dass Ihre Änderung die Leistung verbessern würde, aber es wäre nützlich, die "Vorher" -Ergebnisse anzugeben, um die Verbesserungen zu vergleichen.
Nun, wir wissen aus anderen Fragen in diesem Forum Folgendes:
Daher würde ich vorschlagen, dass das Beispiel, das Sie gefunden haben, wahrscheinlich eines von potenziell vielen Juwelen ist, die im Code versteckt sind, der entweder vor langer Zeit und / oder von einem weniger erfahrenen Entwickler geschrieben wurde. Wie ein Großteil des Kerncodes (und des Community-Codes!) Wäre er an einem kleinen Datensatz getestet und nicht kampferprobt worden, sodass die Leistung möglicherweise nicht genau überwacht wurde.
Ist Ihre Verbesserung vorteilhaft und besser auf bewährte Verfahren ausgerichtet als der ursprüngliche Code? Ja. Sie als Community-Magento [1.x] -Entwickler können jedoch keine Verbesserungsvorschläge einbringen, wie Sie es mit Magento 2 tun. Mein Vorschlag wäre daher, dies in einem lokalen Modul zu implementieren, wenn Sie es für die Leistung in einem Ihrer Geschäfte benötigen , oder ignorieren Sie es, wenn es Sie nicht betrifft, Sie es aber bei Recherchen bemerkt haben.
Ich bin mir sicher, dass die Walk-Methode in Varien_Data_Collection als Aktualisierung Ihrer Fragenbearbeitung einen beliebigen Rückruf akzeptiert, sodass Sie sie für alles verwenden können, was Sie wahrscheinlich möchten. Um das Ereignis im ursprünglichen Beispiel auszulösen, können Sie dies sowohl mit der Walk-Funktion als auch mit dem Löschen tun.
Der einzige Grund, warum ich mir vorstellen kann, dass das Laden des Produkts vor dem Löschen von Nutzen ist, könnte sein, dass die an dieses Ereignis angehängten Beobachter möglicherweise einen vollständigen Datensatz benötigen, der nicht verfügbar ist, ohne das Produkt zuerst zu laden. Wenn dies der Fall ist, würde dies erklären, warum sie einen Singleton anstelle eines Modells verwenden, um den Objekt-Overhead zumindest zu minimieren.
quelle
Ich denke, sie tun es, um das
catalog_controller_product_delete
Ereignis auszulösen, das von Mage_Tag verwendet wird.catalog_product_delete_before
odercatalog_product_delete_after
würde bedeuten, dass dies unnötig war, obwohl ich denken würde. Ich frage mich, ob dieses bestimmte Ereignis auch für die Protokollierung von Administratoraktionen verwendet wird.quelle
massDelete()
CustomerController.php
Ich denke, Massenlöschung sollte funktionieren wie das Löschen eines einzelnen (vollständig geladenen) Produkts.
Denn
$collection->delete()
die Antwort ist schon gegeben. Wenn Sie nicht auslösendeleter_before
,delete_after
könnte ich möglicherweise einige Erweiterungen brechen und einige im Kern verwendete Beobachter umgehen.$collection->walk('delete')
würde möglicherweise funktionieren, hat aber immer noch den Nachteil, dass Produktdaten nicht vollständig sind. Dies kann auch benutzerdefinierte Beobachter beschädigen, wenn sie auf zusätzliche Daten angewiesen sind, z. B. ein Lagerartikelobjekt.Ich denke, wenn Sie ändern
->addAttributeToSelect('entity_id')
zu->addAttributeToSelect('*')
und fügen Sie->setFlag('require_stock_items', true)
(Bestandsdaten zu Produkten hinzuzufügen) ist es nicht besser abschneiden wird dann „Loop-löschen“.Sieht nach schlechtem Stil aus, aber ich denke, es ist richtig für beide Massenlöschaktionen.
Ich benutze
walk()
und auchdelete()
für kundenspezifische Modelle, aber ich weiß, dass es keine Beobachter gibt oderentity_id
genug ist. Nur zu erwähnen,walk()
würde mit allen Ereignissen funktionieren, die im Kern verwendet werden, da sie nur verwendet werden$product->getId()
, aber Sie wissen nichts über Beobachter von Drittanbietern.quelle