Thu thập hiệu quả Gọi, Lọc và Tải


15

Ngay bây giờ tôi đang tái sử dụng rất nhiều bộ sưu tập được lồng trong các vòng lặp foreach. Có thể di chuyển những thứ này lên một vài cấp độ? Hiện tại tôi buộc phải tải lại các bộ sưu tập có 51k + thực thể lặp đi lặp lại, điều này làm mọi thứ chậm đi rất nhiều. Cụ thể là bộ sưu tập kitinventory.

<?php
class Codespace_Module_Helper_Item extends other_one{

function functionOne($collection){
    ...
    $data = $collection->getData();
    foreach($data as $item){
        $this->_functionTwo($item);
    }
    ...
}

function _functionTwo($item){
    $model = Mage::getModel('catalog/product');
    $id = $model->getIdBySku($item['sku']);
    $inventoryStatus = Mage::getResourceSingleton('catalog/product')->getAttributeRawValue($id, 'product_inventory_status', 1);
    $invStatus = $model->getResource()->getAttribute('product_inventory_status')->getSource()->getOptionText($inventoryStatus);
    if ($invStatus && $id) {
        if ($invStatus !== 'Z') {
            $stockItem = Mage::getModel('cataloginventory/stock_item');
            $stockItem->setData(array());
            $stockItem->loadByProduct($id);
            if ($stockItem->getQty() != $item['quantity']) {
                $stockItem->setQty(item['quantity']);
                $stockItem->save();
                $this->functionThree($item['sku']);
            }
        }
    }
}

function functionThree($sku){
    $collectionOfKits = Mage::getModel('kitinventory/kitinventory')->getCollection()->addFieldToFilter('related_sku',$sku);
    if($collectionOfKits->getSize()){
        foreach($collectionOfKits as $kit){
            $kitSku = $kit->getSku();
            $kitCollection = Mage::getModel('kitinventory/kitinventory')->getCollection()->addFieldToFilter('kit_sku',$kitSku)->setOrder('related_sku','ASC');
            ...
            foreach($kitCollection as $component){
                $componentSkus[] = $component->getRelatedSku();
                $componentRequiredQuantity[] = $component->getRequiredQuantity();
            }
            $componentProductCollection = Mage::getModel('catalog/product')->getCollection();
            $componentProductCollection->joinField('qty',
                'cataloginventory/stock_item',
                'qty',
                'product_id=entity_id',
                '{{table}}.stock_id=1',
                'left');
            $componentProductCollection->addAttributeToFilter('sku', array('in' => $componentSkus));
            foreach($componentProductCollection as $component){
                $quantity = $component->getQty();
                ...
            }
            $kitId= Mage::getModel('catalog/product')->getIdBySku($kitSku)
            $kitStockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($kitId);
            $this->functionFour($kitStockItem,$kitSku,$amountOfKitsPossible);
        }
    }
}

function functionFour($kitStockItem,$kitSku,$amountOfKitsPossible){
    ...
    $kitStockItem->setQty($quantity);
    $kitStockItem->save();
    ...
}

EDIT: đây là chức năng hiện tại tôi đã nghĩ ra, tôi vẫn nghĩ có một cách tốt hơn để xử lý các bộ sưu tập này.


Những loại bộ sưu tập được thông qua functionOne($collection)? Theo thứ tự kích thước / số lượng vật phẩm sẽ theo thứ tự nào? Có nhất thiết phải vòng qua nó để lấy SKU không?
7ochem

@ 7ochem Đó là một bộ sưu tập tùy chỉnh được xây dựng từ dữ liệu hàng tồn kho mới mà chúng tôi nhận được từ hệ thống quản lý kho của chúng tôi. nó chứa tên của vật phẩm, số lượng vật phẩm trên tay và sku của vật phẩm. Nó có khả năng chứa 60k + phần tử.
Easymoden00b

Câu trả lời:


9

Có một vài điều bạn có thể làm việc;

  • không truyền qua tham chiếu, vì vậy sử dụng bộ nhớ bổ sung, bạn có thể truyền các đối tượng, nhưng các mảng không thể được truyền theo tham chiếu theo mặc định. Hoặc thêm một &khai báo tham số chức năng nhưfunction hello(array &$world)
  • kiểm tra không hợp lệ, nếu cái gì đó không có trở lại ngay lập tức. Đừng cố tìm thứ gì đó không có ở đó
  • đôi khi có thể đọc được
    • thêm một số tài liệu (để bạn có thể hiểu nếu bạn thấy nó trong một vài ngày, tháng, năm)
    • ifbáo cáo thông minh hơn để nhận được ít thụt lề
  • các chức năng chỉ nên có một mục đích, cập nhật chứng khoán hoặc cập nhật liên quan, không phải cả hai, vì vậy thậm chí có thể cắt một số chức năng trong các chức năng thậm chí nhỏ hơn. Cố gắng tạo ra logic như vậy trong tâm trí của bạn, và làm lại từ đó.
  • Hãy xem ->cleanModelCache()->clearInstance()từ Mage_Core_Model_Model_Abstractđể xóa dữ liệu cơ bản cho một số đối tượng, có thể tăng tốc mọi thứ.
  • của tất cả những điều khác đã được nói.

Đã thêm phiên bản cập nhật của mã của bạn với một số đề xuất nội tuyến về mã hiện tại của bạn, tôi có thể tiếp tục một chút, nhưng hiện tại nó sẽ không thêm nhiều hơn vào mã.

Chức năng 1: Mục đích là đi bộ sưu tập

    /**
     * Walk collection
     * 
     * @param Mage_Core_Model_Resource_Db_Collection_Abstract $collection
     * @return void
     */
    public function functionOne($collection)
    {
        // ...

        // Walk collection, create references instead of passing array data
        foreach ($collection as $item) {

            // Update stock for product
            if (!$this->_functionTwo($item)) {
                // Not updated, continue next
                continue;
            }

            // Update related products
            $this->_functionThree($item); // Use same object again, no extra memory is used
        }

        // ...
    }

Chức năng 2: Mục đích là cập nhật chứng khoán nếu thay đổi

    /**
     * Update stock item if changed, returns true if updated
     * 
     * @param Mage_Core_Model_Model_Abstract $item
     * @return bool
     */
    function _functionTwo($item)
    {
        $model = Mage::getModel('catalog/product');
        /** @var $model Mage_Catalog_Model_Product */

        $id = $model->getIdBySku($item->getData('sku'));

        if (!$id) {
            // no id found, so stop looking nothing up
            return false;
        }

        // Get option value for store 1
        $inventoryStatus = $model->getResource()
                ->getAttributeRawValue($id, 'product_inventory_status', 1);

        if (!$inventoryStatus) {
            // No need for another lookup in db, because the status isn't set
            return false;
        }

        $invStatus = $model->getResource()
                ->getAttribute('product_inventory_status')
                ->setStoreId(0) // Get admin value
                ->getSource()
                ->getOptionText($inventoryStatus);

        if (!$invStatus) {
            // No need for another lookup in db, because the status has no text
            return false;
        }

        if ($invStatus === 'Z') {
            // Inventory status to not change something
            return false;
        }

        $stockItem = Mage::getModel('cataloginventory/stock_item');
        /** @var $stockItem Mage_CatalogInventory_Model_Stock_Item */

        // $stockItem->setData(array()); // unneeded piece of code
        $stockItem->loadByProduct($id);

        if ($stockItem->getQty() == $item->getData('quantity')) {
            // Valid stock
            return false;
        }

        // Update stock
        $stockItem->setQty($item->getData('quantity'));
        $stockItem->save();

        // End function and call function three separately, does something else
        return true;
    }

Chức năng 3: Mục đích cập nhật các mục chứng khoán liên quan

    /**
     * Update related stock items, return false if no related items are found
     * 
     * @param Mage_Core_Model_Model_Abstract $item
     * @return bool
     */
    function functionThree($item)
    {

        $collectionOfKits = Mage::getModel('kitinventory/kitinventory')
                ->getCollection()
                ->addFieldToFilter('related_sku', $item->getData('sku')); // Check if your indexes are set on these columns

        if (!$collectionOfKits->getSize()) {
            // Nothing found to relate to
            return false;
        }

        $connection = Mage::getSingleton('core/resource')
                ->getConnection('core_write');

        // Walk kits
        foreach ($collectionOfKits as $kit) {

            // getData is slightly faster then getSku(unless you've implemented it in your model)
            // getSku -> __call('getSku') -> get -> lowercase('sku') -> getData('sku') | note, Magento has some internal caching in this 
            $kitSku = $kit->getData('sku');

            $kitCollection = Mage::getModel('kitinventory/kitinventory')
                    ->getCollection()
                    ->addFieldToFilter('kit_sku', $kitSku)
                    ->setOrder('related_sku', 'ASC');

            // Use just a fetchAll to create a fast db query
            $select = $kitCollection->getSelect();

            $select->reset(Zend_Db_Select::COLUMNS)
                    ->distinct()
                    ->columns('related_sku')
                    ->columns('required_quantity');

            // Fetch component sku
            $componentSkus = $connection->fetchAll($select, 0);

            // Fetch required quantity
            $componentRequiredQuantity = $connection->fetchCol($select, 1);

            // ...

            $componentProductCollection = Mage::getModel('catalog/product')
                    ->getCollection()
                    ->joinField('qty',
                    'cataloginventory/stock_item',
                    'qty',
                    'product_id = entity_id',
                    '{{table}}.stock_id = 1',
                    'left');
            $componentProductCollection->addAttributeToFilter('sku', array('in' => $componentSkus));

            // Next line will invoke a load on the product collection
            foreach ($componentProductCollection as $component) {
                $quantity = $component->getQty();

                // ...

            }
            // You could choose to do a fetchAll here instead to get just the data you need
            $connection = $componentProductCollection->getConnection();

            foreach ($connection->fetchAll($componentProductCollection->getSelect()) as $row) {
                // Will have a array here
                $quantity = $row['quantity'];

                // ... -- do not not which funky magic happens here
            }


            $kitId = Mage::getModel('catalog/product')
                    ->getIdBySku($kitSku);
            if (!$kitId) {
                // No id
                continue;
            }

            // You could also take a look if you can sum the stock and do a single update instead
            $kitStockItem = Mage::getModel('cataloginventory/stock_item')
                    ->loadByProduct($kitId);
            $this->functionFour($kitStockItem, $kitSku, $amountOfKitsPossible);

            // Or something like this, update single field
            $connection->update($kitStockItem->getResource()->getMainTable(), array('qty' => $quantity), 'item_id = ' . $kitStockItem->getId());
        }

        return true;
    }

Chức năng 4: Phải thực hiện một số dự đoán may mắn (hoặc không may mắn), vì bây giờ nó là một chức năng vô dụng, có thể được thêm vào như trong Chức năng 3.

    /**
     * Save stock item if changed and something else, rather not say ;-)
     * 
     * @param Mage_Catalog_Inventory_Model_Stock_Item $kitStockItem
     * @param string $kitSku
     * @param int $amountOfKitsPossible Guessed it
     */
    function functionFour($kitStockItem, $kitSku, $amountOfKitsPossible)
    {

        // ...

        // Do not know the rest of the code, so I wouldn't know which I could optimize here
        // If it isn't to serious, you could look at a single query and not hitting extra functions

        // Check if changed
        if ($quantity !=$kitStockItem->getData('qty')) {
            $kitStockItem->setQty($quantity);
            $kitStockItem->save();
        }        

        // ...

    }
}

Bạn là người đàn ông. Tôi tương đối chắc chắn điều này sẽ hoạt động và nếu điều này cho thấy sự cải thiện rõ rệt về thời gian xử lý, có thể là tài liệu tham khảo của tôi để thao tác các bộ sưu tập!
Easymoden00b

Một vài lỗi nhỏ, nhưng nó được xây dựng tốt hơn nhiều so với của tôi.
Easymoden00b

5

Tôi muốn thêm nó dưới dạng một bình luận nhưng tôi chưa có đủ đại diện. Hãy xem cách các lưới lõi Magento tham gia sản phẩm qty vào danh mục / bộ sưu tập sản phẩm tại đây: https://github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code/core/Mage/Adminhtml /Block/Catalog/Sản phẩm / Graz.php # L65

Nếu bạn tham gia vào bảng để có được qty, bạn không phải gọi điều này trong một vòng lặp: Mage::getModel('cataloginventory/stock_item')->loadByProduct($product)->getQty();

$productCollection = Mage::getModel('catalog/product')->getCollection();
$productCollection->joinField('qty',
    'cataloginventory/stock_item',
    'qty',
    'product_id=entity_id',
    '{{table}}.stock_id=1',
    'left');
$productCollection->addAttributeToFilter('sku',array('in' => $relatedSkus));
foreach($productCollection as $product){
    $quantity = $product->getQty();
    ...// now you have your qty without having to load the product model.
}

Cách khác là để xem liệu bạn có thể lưu trữ kết quả của quy trình chuyên sâu hệ thống này hay không. Có lẽ bạn có thể tạo một bảng cơ sở dữ liệu thứ hai để lưu trữ kết quả và làm cho nó được làm mới giống như một chỉ số magento.


quan tâm để chia sẻ làm thế nào tôi có thể gọi thông tin này theo cách tương tự với mã ở trên? Ngoài ra, nếu tôi tạo các bộ sưu tập sản phẩm và gán chúng cho một biến lớp, tôi có thể gọi bộ sưu tập đó trong toàn bộ mã không? Việc lọc (như được hiển thị trong mã) có ảnh hưởng đến biến lớp hay nó sẽ không thay đổi nếu tôi gán bộ sưu tập được lọc này cho biến khác?
Easymoden00b

Tôi đã thêm một ví dụ về cách tham gia lĩnh vực này, nhưng đây chỉ là một tối ưu hóa nhỏ. Có: Bạn có thể lưu kết quả dưới dạng các biến lớp và gọi chúng ở nơi khác. Nhưng: Tôi nghĩ rằng bạn sẽ phải khởi tạo một mô hình mới mỗi lần bạn muốn thay đổi bộ lọc (có thể đánh bại mục đích.)
Eric Seastrand 20/03/2015

Cảm ơn bạn, nó xuất hiện như tôi đã sợ. Cảm ơn ví dụ về tối ưu hóa này. Bất kỳ người nào khác bạn có thể nghĩ đến? Tôi sẽ giải thích về việc sử dụng mỗi bộ sưu tập một chút trong ví dụ mã ở trên.
Easymoden00b

3

Bạn không cần phải tải lại mô hình nhiều lần, Mage::getModel()với một tham chiếu là đủ mà không cần biết các mô hình tài nguyên của bạn được thiết lập khó khăn như thế nào nếu nó được khởi tạo lại mỗi lần trong bộ nhớ và trong các vòng lặp đó bạn sẽ bị rò rỉ / hết bộ nhớ gây ra trao đổi đĩa có thể xảy ra.

Một bộ sưu tập để cai trị tất cả. Tái cấu trúc các hàm để chỉ tham chiếu một bộ sưu tập. Điều này giống với SQL chuẩn và lập trình thủ tục. Dành thêm một chút thời gian để điều tra các bộ sưu tập và mô hình tài nguyên của bạn về cách bạn có thể nhận được tất cả dữ liệu bạn cần từ SQL một lần, có thể hai lần và sau đó có đủ bộ nhớ cũng như tham chiếu dữ liệu để lặp lại để hiển thị / thao tác. Việc lưu trữ một kết quả trong bộ đệm so với nhiều người cũng dễ dàng hơn, đây cũng là trường hợp tương tự đối với các cơ chế bộ nhớ đệm tích hợp của MySQL, vì các yêu cầu thường xuyên đủ lớn sẽ gây ra vấn đề hoán đổi đĩa tương tự.

Lưu I / O

Vinai có một ví dụ điển hình về việc thực hiện cùng một cách tiếp cận:

Tài liệu tham khảo :

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.