Magento:膨大な受注コレクションをフィルタリング


7

大量の販売注文をフィルタリングしようとしています。その中に500万以上のレコードがあります。以下は注文コレクションを取得するためのコードです。また、目的の列を取得するためにいくつかの結合を配置します

    $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'));

addAttributeToFilterこのコレクションに関数を適用すると、結果を取得するのに10分かかります。私の質問は、コレクションをフィルタリングする効率的かつ高速な方法があるということです

更新

以下は私のフィルターロジックです。別のフィルターを使用して注文を検索したい

    $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))));
    }

回答:


2

非常に大きなコレクションを操作する場合、致命的なエラーAllowed memory size of X bytes枯渇またはTime outのいずれかになる可能性が高くなります。あなたの場合、それは起こりませんが、それは長い時間がかかります。

幸い、ほとんどの人が気づいていないにもかかわらず、MagentoはそのためのソリューションであるMage_Core_Model_Resource_Iteratorモデルを提供しています。それは基本的に、コードで行うようにすべての結果を一度にロードする代わりに、イテレーター(つまり1つずつ)を介してデータベースからデータを取得できるようにします。

イテレータはwalk()コレクションデータベースクエリ文字列コールバックメソッドの 2つのパラメータを必要とするメソッドを使用しています

walk()メソッドのコードは次のようになります。

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;
}

(結果をループする場合、またはそれをエクスポートする場合)コードが正確に何をしているのかを言っていないので、使用できる例を紹介します。

貼り付けたコードの後で、次のことができます。

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

同じクラスで、collectionCallbackメソッドを作成する必要があります。

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

addAttributeToFilterメソッドと比較してパフォーマンスの点でどれほど優れているかはわかりませんが、このコールバック関数を使用して直接フィルターを実行できます。例:

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

}

さまざまなフィルターで注文を検索したい
Shaheer Ali

@ShaheerAli素晴らしい、walkメソッドはまさにあなたが必要とするものです
デジタルピアニズムのRaphael

@Raphelは私の更新された質問を確認してください。ウォーク機能を使用して同じ結果を得るには
Shaheer Ali

@Raphel at Digital。私はあなたの解決策を試しましたが、同じ時間がかかり、結果も得られません:(
Shaheer Ali

0

データの最後のサイズを処理するための高速で最も効果的な方法は、MagentoでMY SQLクエリを使用して目的の列データを取得することです。

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

選択を実行するには、次のようにします。

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

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

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

1
使用することfetchAllは間違いなく最速で最も効果的な方法ではありません
デジタルピアニズムのRaphael
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.