您在示例腳本中使用了很多對象包裝器。像load
這樣的方法封裝成多個循環會產生巨大的延遲,並可能會導致巨大的內存使用量(基於您的產品集合大小)。
當我在前幾天提到這個問題時,我決定使用直接的ORM方法而不是對象來獲得更好的性能。
有兩種可能的方式來顯示暢銷書。使用匯總的暢銷書表(如sales_bestsellers_aggregated_daily
)的資源消耗較少,但它有巨大的缺點 - 這些表中的數據不會自動更新。它用於管理報告部分,只有在您選擇刷新統計信息時纔會更新。
另一個更可靠的方法是加入sales_flat_order_item
表來檢索每個產品的sales_qty。顯然它更耗費資源,因爲你必須自己計算。
在我的腳本中,我選擇了後一種路徑。我已經修改它以符合您的邏輯要求。此外,我添加了幾個joins
以獲得類別名稱,您可能不需要。但足夠的說話:)這裏是我的test.php
shell腳本的代碼:
<?php
require_once 'abstract.php';
/**
* Magento Test Bestsellers script
*
* @category Mage
* @package Mage_Shell
*/
class Mage_Shell_Test extends Mage_Shell_Abstract
{
/**
* Run script
*
*/
public function run()
{
// benchmarking
$memory = memory_get_usage();
$time = microtime();
echo "Starting mem usage: $memory\n";
$catId = $this->getArg('category');
/** @var $collection Mage_Catalog_Model_Resource_Product_Collection */
$collection = Mage::getResourceModel('catalog/product_collection');
// join sales order items column and count sold products
$expression = new Zend_Db_Expr("SUM(oi.qty_ordered)");
$condition = new Zend_Db_Expr("e.entity_id = oi.product_id AND oi.parent_item_id IS NULL");
$collection->addAttributeToSelect('name')->getSelect()
->join(array('oi' => $collection->getTable('sales/order_item')),
$condition,
array('sales_count' => $expression))
->group('e.entity_id')
->order('sales_count' . ' ' . 'desc');
// join category
$condition = new Zend_Db_Expr("e.entity_id = ccp.product_id");
$condition2 = new Zend_Db_Expr("c.entity_id = ccp.category_id");
$collection->getSelect()->join(array('ccp' => $collection->getTable('catalog/category_product')),
$condition,
array())->join(array('c' => $collection->getTable('catalog/category')),
$condition2,
array('cat_id' => 'c.entity_id'));
$condition = new Zend_Db_Expr("c.entity_id = cv.entity_id AND ea.attribute_id = cv.attribute_id");
// cutting corners here by hardcoding 3 as Category Entiry_type_id
$condition2 = new Zend_Db_Expr("ea.entity_type_id = 3 AND ea.attribute_code = 'name'");
$collection->getSelect()->join(array('ea' => $collection->getTable('eav/attribute')),
$condition2,
array())->join(array('cv' => $collection->getTable('catalog/category') . '_varchar'),
$condition,
array('cat_name' => 'cv.value'));
// if Category filter is on
if ($catId) {
$collection->getSelect()->where('c.entity_id = ?', $catId)->limit(1);
}
// unfortunately I cound not come up with the sql query that could grab only 1 bestseller for each category
// so all sorting work lays on php
$result = array();
foreach ($collection as $product) {
/** @var $product Mage_Catalog_Model_Product */
if (isset($result[$product->getCatId()])) {
continue;
}
$result[$product->getCatId()] = 'Category:' . $product->getCatName() . '; Product:' . $product->getName() . '; Sold Times:'. $product->getSalesCount();
}
print_r($result);
// benchmarking
$memory2 = memory_get_usage();
$time2 = microtime();
$memDiff = ($memory2 - $memory)/1000000;
$timeDiff = $time2 - $time;
echo 'Time spent:' . $timeDiff . "s\n";
echo "Ending mem usage: $memory2\n";
echo "Mem used : {$memDiff}M\n";
}
/**
* Retrieve Usage Help Message
*
*/
public function usageHelp()
{
return <<<USAGE
Usage: php -f test.php -- [options]
php -f test.php -- --category 1
--categories <category> Filter by Category, if not specified, all categories are outputted
help This help
USAGE;
}
}
$shell = new Mage_Shell_Test();
$shell->run();
要使用它只是在你的外殼文件夾中創建一個文件test.php
並插入我提供到文件的代碼。如果您不熟悉命令行php調用,請參閱usageHelp
。
P.S.在那裏添加了一些基準來跟蹤你的mem_usage和時間。
UPDATE進一步審查問題後,我發現更優雅的方式來獲得每個類別的暢銷品只使用Zend_Db
適配器。結果將只包含category_id
=>product_id
連接(不是Magento對象),但它更容易和整體更好。此代碼應標杆塊之間進入run
功能:
$catId = $this->getArg('category');
/** @var $resource Mage_Core_Model_Resource */
$resource = Mage::getModel('core/resource');
/** @var $adapter Zend_Db_Adapter_Abstract */
$adapter = $resource->getConnection('core_read');
$select = $adapter->select()
->from(array('c' => $resource->getTableName('catalog/category')), array('cat_id'=>'entity_id'))
->join(array('ccp' => $resource->getTableName('catalog/category_product')), 'c.entity_id = ccp.category_id', array())
->join(array('oi' => $resource->getTableName('sales/order_item')), 'ccp.product_id = oi.product_id', array('max_qty' => new Zend_Db_Expr('SUM(oi.qty_ordered - oi.qty_canceled)'), 'product_id' => 'product_id'))
->where('oi.parent_item_id is null')
->group('c.entity_id')
->group('oi.product_id')
->order('entity_id ASC')
->order('max_qty DESC');
if ($catId) {
$select->where('c.entity_id = ?', $catId);
}
$res = $adapter->fetchAll($select);
$result = array();
foreach ($res as $oneRes) {
if (isset($result[$oneRes['cat_id']])) {
continue;
}
$result[$oneRes['cat_id']] = $oneRes;
}
array_walk($result, function($var, $key) {
echo 'Category Id:' . $key . ' | Product Id:' . $var['product_id'] . ' | Sales Count:' . $var['max_qty'] . "\n";
});
對不起,我遲到的答覆,但感謝你的信息的答案!運行腳本會返回四個空數組。由於到目前爲止還沒有銷售產品,我不驚訝他們完全是空的(呃,至少不應該是內部的文本字符串?),但我得到了四個。我有四個父類別,但將$ catId定義爲「17」(我的一個子類別ID)用於測試目的。我有什麼監督嗎? – HamuSumo
@HamuSumo如果您願意,請查看我的更新 –
請注意,這些sales_bestsellers_aggregated會被magneto的cron調度程序系統中的cron作業填充 –