การรวบรวมการกรองและการโหลดที่มีประสิทธิภาพ


15

ตอนนี้ฉันกำลังใช้คอลเลกชันจำนวนมากที่ซ้อนกันอยู่ภายในลูปด้านหน้า เป็นไปได้ไหมที่จะย้ายสิ่งต่าง ๆ เหล่านี้ขึ้นมาสองสามระดับ? ปัจจุบันฉันถูกบังคับให้โหลดคอลเล็กชันที่มีเอนทิตี 51k ขึ้นไปซ้ำแล้วซ้ำอีกซึ่งทำให้สิ่งต่าง ๆ ช้าลงอย่างมาก โดยเฉพาะคอลเลกชัน 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();
    ...
}

แก้ไข: นี่คือฟังก์ชั่นปัจจุบันที่ฉันมีมาฉันยังคิดว่ามีวิธีที่ดีกว่าในการจัดการคอลเลกชันเหล่านี้


สิ่งที่ชนิดของคอลเลกชันจะถูกส่งไปfunctionOne($collection)? ขนาด / จำนวนรายการจะเรียงตามลำดับอย่างไร จำเป็นหรือไม่ที่จะต้องวนซ้ำเพื่อให้ได้ SKU?
7ochem

@ 7ochem เป็นการรวบรวมแบบกำหนดเองที่สร้างขึ้นจากข้อมูลสินค้าคงคลังใหม่ที่เราได้รับจากระบบการจัดการสินค้าคงคลังของเรา มันมีชื่อของรายการปริมาณของรายการในมือและ sku ของรายการ มันอาจมีองค์ประกอบ 60k +
easymoden00b

คำตอบ:


9

มีบางสิ่งที่คุณสามารถทำงานได้;

  • ไม่ผ่านการอ้างอิงดังนั้นการใช้หน่วยความจำเพิ่มเติมคุณสามารถส่งผ่านวัตถุได้ แต่ค่าเริ่มต้นไม่สามารถส่งผ่านอาร์เรย์ได้ หรือเพิ่ม&ในการประกาศพารามิเตอร์ฟังก์ชั่นเช่นfunction hello(array &$world)
  • การตรวจสอบที่ไม่ถูกต้องหากสิ่งที่ไม่ได้กลับมีทันที อย่าพยายามหาบางอย่างที่ไม่ได้อยู่ที่นั่น
  • บางครั้งการอ่านอาจเป็นเรื่องยาก
    • เพิ่มเอกสาร (เพื่อให้คุณสามารถเข้าใจถ้าคุณเห็นมันในไม่กี่วัน, พระ, ปี)
    • ifงบที่ฉลาดขึ้นเพื่อลดการเยื้อง
  • ฟังก์ชั่นควรมีเพียงจุดประสงค์เดียวอัพเดตสต็อคหรืออัพเดตที่เกี่ยวข้องไม่ใช่ทั้งสองอย่างดังนั้นอาจตัดบางฟังก์ชั่นในฟังก์ชั่นที่เล็กกว่า พยายามสร้างตรรกะดังกล่าวในใจและทำใหม่จากที่นั่น
  • ลองดู->cleanModelCache()->clearInstance()จากMage_Core_Model_Model_Abstractเพื่อล้างข้อมูลพื้นฐานสำหรับวัตถุบางอย่างสามารถเร่งความเร็วของสิ่งต่างๆได้
  • ของหยาบสิ่งอื่น ๆ ทั้งหมดที่ได้รับการกล่าวแล้ว

เพิ่มเวอร์ชันที่อัปเดตของโค้ดของคุณพร้อมกับคำแนะนำแบบอินไลน์ในโค้ดปัจจุบันของคุณฉันสามารถใช้งานได้อีกเล็กน้อย แต่ในปัจจุบันจะไม่เพิ่มไปอีก

ฟังก์ชั่น 1: วัตถุประสงค์คือการเดินคอลเลกชัน

    /**
     * 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
        }

        // ...
    }

ฟังก์ชั่น 2: วัตถุประสงค์คือการปรับปรุงสต็อกถ้ามีการเปลี่ยนแปลง

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

ฟังก์ชั่น 3: วัตถุประสงค์ในการอัพเดทรายการสต็อคที่เกี่ยวข้อง

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

ฟังก์ชั่น 4: ต้องคาดเดาโชคดี (หรือโชคร้าย) สำหรับตอนนี้มันเป็นฟังก์ชั่นที่ไร้ประโยชน์สามารถเพิ่มได้เช่นเดียวกับในฟังก์ชั่น 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();
        }        

        // ...

    }
}

คุณคือผู้ชาย ฉันค่อนข้างแน่ใจว่าจะใช้งานได้และหากสิ่งนี้แสดงให้เห็นถึงการปรับปรุงที่ชัดเจนในเวลาประมวลผลอาจเป็นข้อมูลอ้างอิงแบบไปสู่การจัดการคอลเลกชันของฉัน!
easymoden00b

ข้อผิดพลาดเล็ก ๆ น้อย ๆ แต่ก็สร้างได้ดีกว่าของฉันมาก
easymoden00b

5

ฉันต้องการเพิ่มสิ่งนี้เป็นความคิดเห็น แต่ฉันยังไม่มีตัวแทนที่เพียงพอ ลองดูวิธีการที่แกนกลางวีโอไอพีเข้าร่วมจำนวนสินค้าในแคตตาล็อก / คอลเลกชันผลิตภัณฑ์ที่นี่: https://github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code/core/Mage/Adminhtml /Block/Catalog/Product/Grid.php#L65

หากคุณเข้าร่วมตารางเพื่อรับจำนวนคุณไม่ต้องเรียกสิ่งนี้ในการวนซ้ำ: 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.
}

อีกทางเลือกหนึ่งคือดูว่าคุณสามารถแคชผลลัพธ์ของกระบวนการที่เข้มข้นของระบบนี้ได้หรือไม่ บางทีคุณอาจสร้างตารางฐานข้อมูลที่สองเพื่อเก็บผลลัพธ์และให้รีเฟรชเหมือนดัชนีวีโอไอพี


สนใจแบ่งปันวิธีที่ฉันสามารถเรียกข้อมูลนี้ในลักษณะที่คล้ายคลึงกับรหัสด้านบน นอกจากนี้ถ้าฉันสร้างคอลเลกชันผลิตภัณฑ์และกำหนดให้กับตัวแปรคลาสฉันจะสามารถเรียกคอลเลกชันนั้นตลอดทั้งรหัสได้หรือไม่ การกรอง (ดังที่แสดงในรหัส) จะมีผลกับตัวแปรคลาสหรือไม่หรือจะยังคงไม่เปลี่ยนแปลงถ้าฉันกำหนดคอลเลกชันที่กรองนี้ให้กับตัวแปรอื่นหรือไม่
easymoden00b

ฉันได้เพิ่มตัวอย่างวิธีเข้าร่วมฟิลด์ แต่นี่เป็นการเพิ่มประสิทธิภาพเพียงเล็กน้อยเท่านั้น ใช่: คุณสามารถบันทึกผลลัพธ์เป็นตัวแปรคลาสและโทรหาที่อื่นได้ แต่: ฉันคิดว่าคุณจะต้องยกตัวอย่างรุ่นใหม่ทุกครั้งที่คุณต้องการเปลี่ยนการกรอง (อาจเอาชนะวัตถุประสงค์)
Eric Seastrand

ขอบคุณดูเหมือนว่าฉันกลัว ขอบคุณสำหรับตัวอย่างของการเพิ่มประสิทธิภาพนี้ คนอื่น ๆ ที่คุณนึกออก ฉันจะอธิบายเกี่ยวกับการใช้งานของคอลเลกชันแต่ละบิตในตัวอย่างรหัสข้างต้น
easymoden00b

3

คุณไม่จำเป็นต้องรีโหลดโมเดลซ้ำไปซ้ำมาโดยMage::getModel()มีการอ้างอิงเพียงพอโดยไม่ทราบว่าโมเดลรีซอร์สของคุณติดตั้งยากที่จะบอกว่ามันถูกเริ่มต้นใหม่ทุกครั้งในหน่วยความจำและในลูปที่คุณจบลง หน่วยความจำที่ทำให้เกิดการสลับดิสก์อาจเกิดขึ้นได้

หนึ่งคอลเลกชันที่จะปกครองพวกเขาทั้งหมด การกำหนดฟังก์ชันใหม่เพื่ออ้างอิงคอลเลกชันเดียวเท่านั้น นี่คือเดียวกันกับ SQL มาตรฐานและการเขียนโปรแกรมขั้นตอน ใช้เวลาสักครู่ในการตรวจสอบคอลเล็กชันและโมเดลทรัพยากรของคุณเกี่ยวกับวิธีที่คุณสามารถรับข้อมูลทั้งหมดที่คุณต้องการจาก SQL หนึ่งครั้งอาจมีสองครั้งจากนั้นมีหน่วยความจำเพียงพอและอ้างอิงข้อมูลเพื่อวนซ้ำเพื่อแสดง / จัดการ นอกจากนี้ยังง่ายต่อการจัดเก็บหนึ่งผลลัพธ์ในแคชเทียบกับจำนวนมากนี่เป็นกรณีเดียวกันสำหรับกลไกการแคชในตัวของ MySQL เช่นกันเนื่องจากคำขอบ่อยที่มีขนาดใหญ่พอจะทำให้เกิดปัญหาการสลับดิสก์เดียวกัน

บันทึก I / O

Vinai มีตัวอย่างที่ดีของการใช้แนวทางเดียวกัน:

การอ้างอิง :

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.