Magento 1: Leistungsoptimierungen zum Löschen von Entitäten

10

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.phpmit 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: walkMethode

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_deleteEreignis ausgelöst wird, da derselbe Code an mehreren Stellen (überprüfen Sie die massDeleteMethoden) 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

Raphael beim digitalen Pianismus
quelle
3
Ich denke, es liegt am Ereignis. Aber ich stimme Ihnen zu, es ist ein schlechter Stil, insbesondere die Verwendung 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 der walk()Verknüpfung.
Fabian Schmengler
1
@fschmengler Ja, ich habe auch über das Ereignis nachgedacht, aber wie ich in meiner Bearbeitung sagte, geschieht es an vielen Orten, an denen kein Ereignis ausgelöst wird.
Raphael bei Digital Pianism
3
Nicht überraschend. 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.
Fabian Schmengler
5
@fschmengler Ein Sammlungslöschvorgang führt auch einen Löschvorgang für jedes einzelne Element durch, umgeht jedoch das Löschen des Caches und das Auslösen einiger Magento- und Indexerereignisse. Da muss der Unterschied herkommen.
Vinai
2
@ Vinai du hast recht. Wunschdenken auf meiner Seite
Fabian Schmengler

Antworten:

4

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

Randnotiz, aber Sie sollten sich die Verwendung des Varien Profiler dafür ansehen!

Mein benutzerdefinierter Code ist 2 Sekunden schneller und verbraucht 0,4 MB weniger

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.

Gibt es einen Grund, warum das Magento-Kernteam die walk('delete')Produkte nicht anstelle des Ladens in einer Schleife verwendet hat (was wir alle wissen, ist eine sehr, sehr schlechte Praxis)?

Nun, wir wissen aus anderen Fragen in diesem Forum Folgendes:

  • Die Magento-Codebasis hat sich über viele Jahre entwickelt und weiterentwickelt
  • Es haben viele Entwickler daran gearbeitet
  • Die Magento-Kernentwicklungs-Workflow-Prozesse haben sich im Laufe der Zeit, in der sie an der Plattform gearbeitet haben, dramatisch verbessert und haben moderne Best Practices und Techniken bis zu dem Punkt eingeholt, an dem Magento 2 nun viele führende moderne Anwendungsdesign-Praktiken aufweist

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.

Robbie Averill
quelle
Danke, ich habe die Vorher- und Nachher-Ergebnisse zum Beitrag hinzugefügt. Sie denken also, es gibt keinen besonderen Grund außer der Tatsache, dass es sich um alten Code handelt?
Raphael bei Digital Pianism
2
Das wäre meine Vermutung, ja. Das Laden des Produkts vor dem Löschen hat keinen anderen Vorteil als das Auslösen der Ladeereignisse, die für das Löschen nicht relevant sind. Normalerweise laden Sie ein Produkt, um den vollständigen Datensatz zu erhalten, der möglicherweise für einen der an das Ereignis angehängten Beobachter erforderlich ist. In diesem Fall wird erklärt, warum ein Singleton anstelle eines Modells verwendet wird.
Robbie Averill
1
Sehen Sie meine Bearbeitung mit mehr Tests, Ergebnisse sind noch verrückter
Raphael bei Digital Pianism
0

Ich denke, sie tun es, um das catalog_controller_product_deleteEreignis auszulösen, das von Mage_Tag verwendet wird.

catalog_product_delete_beforeoder catalog_product_delete_afterwü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.

Daniel Kenney
quelle
massDelete()CustomerController.php
Ich habe auch darüber nachgedacht
Sehen Sie meine Bearbeitung mit mehr Tests, Ergebnisse sind noch verrückter
Raphael bei Digital Pianism
0

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ösen deleter_before, delete_afterkö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 auch delete()für kundenspezifische Modelle, aber ich weiß, dass es keine Beobachter gibt oder entity_idgenug 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.

sv3n
quelle