Verimli Tahsilat Arama, Filtreleme ve Yükleme


15

Şu anda, foreach döngülerinin içine yerleştirilmiş bir sürü koleksiyonu yeniden kullanıyorum. Bu şeyleri birkaç seviyeye taşımak mümkün mü? Şu anda 51k + varlığı olan koleksiyonları tekrar tekrar yüklemeye zorlandım, bu da işleri çok yavaşlatıyor. Özellikle kitinventory koleksiyonları.

<?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: Bu şimdiye kadar ortaya çıkan işlevselliği, hala bu koleksiyonları ele almak için daha iyi bir yol olduğunu düşünüyorum.


Ne tür bir koleksiyona geçiliyor functionOne($collection)? Boyut / öğe sayısı hangi sırayla olurdu? SKU'ları almak için bunun üzerinden geçmek gerekli mi?
7ochem

@ 7ochem Envanter yönetim sistemimizden aldığımız yeni envanter verilerinden oluşturulan özel bir koleksiyon. öğenin adını, eldeki öğenin miktarını ve öğenin sku'sunu içerir. Potansiyel olarak 60k + elementler içerebilir.
easymoden00b

Yanıtlar:


9

Üzerinde çalışabileceğiniz birkaç şey var;

  • referans ile geçilmez, bu nedenle fazladan bellek kullanarak nesneleri iletebilirsiniz, ancak diziler varsayılan olarak referans olarak iletilemez. Veya &işlev parametresi bildirimine aşağıdaki gibi birfunction hello(array &$world)
  • geçersiz kontroller, eğer bir şey yoksa hemen iade edin. Orada olmayan bir şey bulmaya çalışmayın
  • okunabilirlik bazen zor olabilir
    • biraz doktor ekleyin (böylece birkaç gün içinde görüyorsunuz, aylar, yıllar)
    • daha ifaz girinti elde etmek için daha akıllı ifadeler
  • fonksiyonların tek bir amacı olmalı, stok güncellemek veya güncelleme ile ilgili değil, her ikisi de değil, bu yüzden daha küçük fonksiyonlarda bile bazı fonksiyonları kesebilirsiniz. Aklınızda böyle bir mantık yaratmaya çalışın ve oradan yeniden çalışın.
  • Bazı nesneler için temel verileri temizlemek için bir göz atın ->cleanModelCache()->clearInstance(), Mage_Core_Model_Model_Abstractişleri hızlandırabilir.
  • daha önce söylenmiş olan tüm diğer şeylerin kaba.

Geçerli kodunuzda bazı satır içi öneriler içeren kodunuzun güncellenmiş bir sürümünü ekledim, biraz devam edebilirim, ancak şu anda buna daha fazla eklemeyecekti.

İşlev 1: Amaç koleksiyonu yürümek

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

        // ...
    }

İşlev 2: Amaç değiştirilirse stoğu güncellemek

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

İşlev 3: İlgili stok kalemlerini güncelleme amacı

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

İşlev 4: Şanslı (ya da şanssız) tahminler yapmak zorunda kaldım, şimdilik bu işe yaramaz bir işlevdir, İşlev 3'te olduğu gibi eklenebilir.

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

        // ...

    }
}

Adamsın. Bunun işe yarayacağından nispeten eminim ve bu işlem süresinde belirgin bir iyileşme gösteriyorsa, koleksiyonları manipüle etmek için referansım olabilir!
easymoden00b

Birkaç küçük hata, ama benimkinden çok daha iyi inşa edildi.
easymoden00b

5

Bunu bir yorum olarak eklemek istedim ama henüz yeterli temsilcim yok. Magento çekirdek ızgaralarının ürün miktarını kataloğa / ürün koleksiyonuna nasıl birleştirdiğine bir göz atın: https://github.com/OpenMage/magento-mirror/blob/magento-1.9/app/code/core/Mage/Adminhtml /Block/Catalog/Product/Grid.php#L65

Adet almak için tabloya katılırsanız, bunu bir döngüde çağırmanız gerekmez: 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.
}

Diğer alternatif, bu sistem yoğun işleminin sonuçlarını önbelleğe alıp alamayacağınızı görmektir. Belki sonuçları depolamak için ikinci bir veritabanı tablosu yapabilir ve bir macenta indeksi gibi yenilemek olabilir.


nasıl bu bilgileri yukarıdaki koda benzer şekilde çağırabilir paylaşmak ister misiniz? Ayrıca, ürün koleksiyonları oluşturup bir sınıf değişkenine atarsam kod boyunca bu koleksiyonu çağırabilir miyim? Filtreleme (kodda gösterildiği gibi) sınıf değişkenini etkiler mi yoksa bu filtrelenmiş koleksiyonu başka bir değişkene atarsam değişmeden kalır mı?
easymoden00b

Alana nasıl katılacağına dair bir örnek ekledim, ancak bu sadece küçük bir optimizasyon. Evet: Sonuçları sınıf değişkenleri olarak kaydedebilir ve başka bir yerde arayabilirsiniz. Ancak: Filtrelemeyi her değiştirmek istediğinizde yeni bir model başlatmanız gerektiğini düşünüyorum (amacı yenebilir.)
Eric Seastrand

Teşekkür ederim, korktuğum gibi görünüyor. Bu optimizasyon örneği için teşekkürler. Aklınıza gelebilecek başkaları var mı? Yukarıdaki kod örneğinde her koleksiyonun kullanımları üzerine biraz açıklayacağım.
easymoden00b

3

Modeli tekrar tekrar yüklemenize gerek yoktur Mage::getModel(), kaynak modellerinizin nasıl kurulduğunu bilmeden bir referans yeterlidir, bellekte her seferinde yeniden başlatıldığını ve bu döngülerde sızdığını / tükendiğini söylemek zor büyük olasılıkla disk takasının oluşmasına neden olabilir.

Hepsine hükmedecek bir koleksiyon. Yalnızca bir koleksiyona başvuruda bulunmak için işlevleri yeniden düzenleme. Bu standart SQL ve prosedürel programlama ile aynıdır. Koleksiyonlarınızı ve kaynak modellerinizi, SQL'den ihtiyacınız olan tüm verileri bir kez, belki iki kez nasıl alabileceğiniz konusunda araştırmak için biraz daha zaman ayırın ve daha sonra yeterli belleğe sahip olmanın yanı sıra görüntüleme / manipülasyon için döngü için verilere referans verin. Bir sonucu önbellekte vs birçok yerde saklamak daha kolaydır, bu da MySQL'in yerleşik önbellekleme mekanizmaları için aynı durumdur, çünkü yeterince büyük olan sık talepler aynı disk takas sorununa neden olacaktır.

G / Ç'yi kaydedin

Vinai aynı yaklaşımı uygulamak için iyi bir örneğe sahiptir:

Kaynaklar :

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.