Magento: Filtern Sie riesige Kundenauftragssammlungen


7

Ich versuche, eine riesige Sammlung von Kundenaufträgen zu filtern. Es gibt mehr als 5 Millionen Datensätze. Unten ist mein Code, um die Auftragssammlung zu erhalten, und ich füge auch einige Verknüpfungen hinzu, um die gewünschten Spalten zu erhalten

    $resource = Mage::getSingleton('core/resource');
    $collection = Mage::getResourceModel('sales/order_grid_collection');

    $collection ->join(
      'sales/order_item',
    '`sales/order_item`.order_id=`main_table`.entity_id',
    array(
    'skus' => new Zend_Db_Expr('GROUP_CONCAT(`sales/order_item`.sku SEPARATOR "</br>")'),
    )
    );



    $collection->getSelect()->joinLeft(array('sfog' => $resource->getTableName('sales_flat_order_grid')),
    'main_table.entity_id = sfog.entity_id',array('sfog.shipping_name','sfog.billing_name'));

    $collection->getSelect()->joinLeft(array('sfo'=>  $resource->getTableName('sales_flat_order')),
    'sfo.entity_id=main_table.entity_id',array('sfo.customer_email','sfo.weight',
    'sfo.discount_description','sfo.increment_id','sfo.store_id','sfo.created_at','sfo.status',
    'sfo.base_grand_total','sfo.grand_total'));

    $collection->getSelect()->joinLeft(array('sfoa'=>  $resource->getTableName('sales_flat_order_address')),
    'main_table.entity_id = sfoa.parent_id AND sfoa.address_type="shipping"',array('sfoa.street',
    'sfoa.city','sfoa.region','sfoa.postcode','sfoa.telephone','sfoa.fax'));

Wenn ich die addAttributeToFilterFunktion auf diese Sammlung anwende, dauert es 10 Minuten, um das Ergebnis abzurufen. Meine Frage ist, ob es eine effiziente und schnelle Möglichkeit gibt, die Sammlung zu filtern

Aktualisieren

Unten sind meine Filterlogiken. Ich möchte eine Bestellung mit verschiedenen Filtern suchen

    $email = Mage::app()->getRequest()->getParam('email');

    $phone = Mage::app()->getRequest()->getParam('phone');

    $postcode = Mage::app()->getRequest()->getParam('postcode');

    $skus = Mage::app()->getRequest()->getParam('skus');

    if($email!='')
    {
        $collection->addAttributeToFilter('sfo.customer_email',$email);
    }

    if($phone!='' && $postcode=='')
    {
        $phone = str_replace(' ', '', $phone); // Replaces all spaces with hyphens.
        $phone = preg_replace('/[^A-Za-z0-9\-]/', '', $phone); // Removes special chars.
        $collection->addAttributeToSearchFilter(
            array(
                array(
                    'attribute' => 'sfoa.telephone',
                    'eq' => $phone
                ),
                array(
                    'attribute' => 'sfoa.fax',
                    'eq' => $phone
                )
            )
        );
    }

    if($postcode!='' && $phone!='')
    {
        $collection->addAttributeToFilter('sfoa.postcode',$postcode);
        $phone = str_replace(' ', '', $phone); // Replaces all spaces with hyphens.
        $phone = preg_replace('/[^A-Za-z0-9\-]/', '', $phone); // Removes special chars.
        $collection->addAttributeToFilter('sfoa.telephone',$phone);
    }

    if($skus!='')
    {
        $sku_array = explode(",",$skus);
        $collection->addAttributeToFilter('sku', array('in' => array('finset' => array($sku_array))));
    }

Antworten:


2

Wenn Sie mit sehr großen Sammlungen arbeiten, besteht eine große Wahrscheinlichkeit, dass entweder ein schwerwiegender Fehler auftritt. Zulässige Speichergröße von X Byte erschöpft oder Timeout . In Ihrem Fall passiert es nicht, aber es dauert viel Zeit.

Glücklicherweise bietet Magento eine Lösung für dieses Mage_Core_Model_Resource_IteratorModell , auch wenn die meisten Menschen sich dessen nicht bewusst sind . Grundsätzlich können Sie Daten über einen Iterator (also einzeln) aus der Datenbank abrufen, anstatt alle Ergebnisse auf einmal zu laden, wie Sie es in Ihrem Code tun.

Der Iterator verwendet die walk()Methode, für die zwei Parameter erforderlich sind: eine Abfragezeichenfolge für die Sammlungsdatenbank und eine Rückrufmethode .

Der walk()Methodencode sieht folgendermaßen aus:

public function walk($query, array $callbacks, array $args=array(), $adapter = null)
{
    $stmt = $this->_getStatement($query, $adapter);
    $args['idx'] = 0;
    while ($row = $stmt->fetch()) {
        $args['row'] = $row;
        foreach ($callbacks as $callback) {
            $result = call_user_func($callback, $args);
            if (!empty($result)) {
                $args = array_merge($args, $result);
            }
        }
        $args['idx']++;
    }

    return $this;
}

Sie sagen nicht genau, was Ihr Code tut (wenn Sie die Ergebnisse durchlaufen oder exportieren möchten), daher gebe ich Ihnen nur ein Beispiel, das Sie verwenden können.

Nach dem eingefügten Code können Sie Folgendes tun:

Mage::getSingleton('core/resource_iterator')->walk($collection->getSelect(), array(array($this, 'collectionCallback')));

In derselben Klasse müssen Sie die collectionCallbackMethode erstellen :

public function collectionCallback($args)
{
    // The data for each entry is stored here
    $data = $args['row'];
    // Do something with the data
}

Ich weiß nicht, wie gut die Leistung im Vergleich zur addAttributeToFilterMethode wäre, aber Sie können den Filter direkt mit dieser Rückruffunktion ausführen. Beispiel:

public function collectionCallback($args)
{
    // The data for each entry is stored here
    $data = $args['row'];
    if ($data['attribute'] != "test") {
        return;
    }

}

Ich möchte die Bestellungen nach verschiedenen Filtern
suchen

@ShaheerAli großartig, die walkMethode ist genau das, was Sie brauchen
Raphael bei Digital Pianism

@Raphel überprüfe meine aktualisierte Frage. Wie kann ich das gleiche Ergebnis mit der Walk-Funktion
erzielen

@Raphel bei Digital. Ich habe Ihre Lösung ausprobiert, aber es dauert genauso lange und gibt mir auch kein Ergebnis :(
Shaheer Ali

0

Die schnellste und effektivste Möglichkeit, mit der letzten Datengröße umzugehen, ist die Verwendung der MY SQL-Abfrage in Magento, um die gewünschten Spaltendaten abzurufen.

$resource = Mage::getSingleton('core/resource');

Um eine Auswahl auszuführen, können Sie Folgendes tun:

$readConnection = $resource->getConnection('core_read');

$query = 'SELECT * FROM ' . $resource->getTableName('custom/model');

$results = $readConnection->fetchAll($query);

1
Verwenden fetchAllist definitiv nicht der schnellste und effektivste Weg
Raphael bei Digital Pianism
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.