Php 如何改进Opencart控制器上的getTotalProducts

Php 如何改进Opencart控制器上的getTotalProducts,php,performance,caching,opencart,Php,Performance,Caching,Opencart,我以前不知道,但是Opencart官方版本中有一个巨大的bug,在一个商店里,当你有很多产品和类别时,它需要花费50秒!!!加载页面。50秒,我查看了一下代码和google,发现这个问题有很好的文档记录,因为几乎每个人都知道这一行导致了一切。(从缓存计数) 在任何地方发布的解决方案都包括注释这一行,顺便说一句,如果我只将$product_total设置为空,至少对我来说效果更好。。像这样 //$product_total = $this->model_catalog_product->

我以前不知道,但是Opencart官方版本中有一个巨大的bug,在一个商店里,当你有很多产品和类别时,它需要花费50秒!!!加载页面。50秒,我查看了一下代码和google,发现这个问题有很好的文档记录,因为几乎每个人都知道这一行导致了一切。(从缓存计数)

在任何地方发布的解决方案都包括注释这一行,顺便说一句,如果我只将$product_total设置为空,至少对我来说效果更好。。像这样

//$product_total = $this->model_catalog_product->getTotalProducts($data);

                $product_total = "";
无论如何,我的问题已经解决了(页面加载只需3秒,而不是50秒),但缺少计数,因此我继续查找,最后我发现这个解决方案,如果您的数据库处理大量产品和类别,它几乎是(直到现在,仍在测试)最好的解决方案

它所做的基本上是将整个代码段包装在一个if块中,然后首先检查文件是否存在于缓存中。如果没有,我们将像正常运行一样运行它,然后将其存储到缓存中。如果是,则使用缓存版本

在Controller/Common/Header.php中,您也可以找到这段代码(在他关于类别的文章中),这里是这个文件中的代码

$this->data['categories']=array()

$categories=$this->model\u catalog\u category->getCategories(0);
foreach($categories作为$category){
如果($category['top'])){
//二级
$children_data=array();
$children=$this->model\u catalog\u category->getCategories($category['category\u id');
foreach($childrenas$child){
$data=数组(
'filter_category_id'=>$child['category_id'],
“筛选子类别”=>true
);
$product\U total=$this->model\u catalog\u product->getTotalProducts($data);
$children_data[]=数组(
'name'=>$child['name']。($this->config->get('config_product_count')?'('$product_total'):''),
'href'=>$this->url->link('product/category','path='。$category['category\u id'..'.$child['category\u id']))
);                      
}
你必须把所有的代码都写进这行
$this->data['categories']=$this->cache->get('categories');
如果(!count($this->data['categories']){
$this->cache->set('categories',$this->data['categories']);
}
到目前为止,它的工作还不错,我希望这能帮助其他人,也请注意,如果你有更好的方法来做这件事,我知道有很多非高级用户在寻找这件事,所以如果你能与我们分享,那就太好了

有谁能想出一个更好的办法来解决这个可怕的慢虫

感谢并希望下一版本的Opencart能够解决这类问题


希望这有帮助。和平

这真的应该进入模型,而不是控制器

我有一个站点有15000多个活动产品。我的方法如下:

public function getTotalProducts($data = array()) {
    if ($this->customer->isLogged()):
        $customer_group_id = $this->customer->getCustomerGroupId();
    else:
        $customer_group_id = $this->config->get('config_customer_group_id');
    endif;  

    $sql = "SELECT COUNT(DISTINCT p.product_id) AS total"; 

    if (!empty($data['filter_category_id'])):
        if (!empty($data['filter_sub_category'])):
            $sql .= " FROM {$this->prefix}category_path cp 
                      LEFT JOIN {$this->prefix}product_to_category p2c 
                        ON (cp.category_id = p2c.category_id)";         
        else:
            $sql .= " FROM {$this->prefix}product_to_category p2c";
        endif;

        if (!empty($data['filter_filter'])):
            $sql .= " LEFT JOIN {$this->prefix}product_filter pf 
                        ON (p2c.product_id = pf.product_id) 
                      LEFT JOIN {$this->prefix}product p 
                        ON (pf.product_id = p.product_id)";
        else:
            $sql .= " LEFT JOIN {$this->prefix}product p 
                        ON (p2c.product_id = p.product_id)";
        endif;
    else:
        $sql .= " FROM {$this->prefix}product p";
    endif;

    $sql .= " LEFT JOIN {$this->prefix}product_description pd 
                ON (p.product_id = pd.product_id) 
              LEFT JOIN {$this->prefix}product_to_store p2s 
                ON (p.product_id = p2s.product_id) 
              WHERE pd.language_id = '" . (int)$this->config->get('config_language_id') . "' 
              AND p.status = '1' 
              AND p.date_available <= NOW() 
              AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'";

    if (!empty($data['filter_category_id'])):
        if (!empty($data['filter_sub_category'])):
            $sql .= " AND cp.path_id = '" . (int)$data['filter_category_id'] . "'"; 
        else:
            $sql .= " AND p2c.category_id = '" . (int)$data['filter_category_id'] . "'";            
        endif;  

        if (!empty($data['filter_filter'])):
            $implode = array();

            $filters = explode(',', $data['filter_filter']);

            foreach ($filters as $filter_id):
                $implode[] = (int)$filter_id;
            endforeach;

            $sql .= " AND pf.filter_id IN (" . implode(',', $implode) . ")";                
        endif;
    endif;

    if (!empty($data['filter_name']) || !empty($data['filter_tag'])):
        $sql .= " AND (";

        if (!empty($data['filter_name'])):
            $implode = array();

            $words = explode(' ', trim(preg_replace('/\s\s+/', ' ', $data['filter_name'])));

            foreach ($words as $word):
                $implode[] = "pd.name LIKE '%" . $this->db->escape($word) . "%'";
            endforeach;

            if ($implode):
                $sql .= " " . implode(" AND ", $implode) . "";
            endif;

            if (!empty($data['filter_description'])):
                $sql .= " OR pd.description LIKE '%" . $this->db->escape($data['filter_name']) . "%'";
            endif;
        endif;

        if (!empty($data['filter_name']) && !empty($data['filter_tag'])):
            $sql .= " OR ";
        endif;

        if (!empty($data['filter_tag'])):
            $sql .= "pd.tag LIKE '%" . $this->db->escape(utf8_strtolower($data['filter_tag'])) . "%'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.model) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.sku) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.upc) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.ean) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.jan) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.isbn) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.mpn) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        $sql .= ")";                
    endif;

    if (!empty($data['filter_manufacturer_id'])):
        $sql .= " AND p.manufacturer_id = '" . (int)$data['filter_manufacturer_id'] . "'";
    endif;

    $cache = md5 ((int)$customer_group_id . serialize ($data));

    $total = $this->cache->get('product.total.products.' . $cache);

    if (!$total):

        $query = $this->db->query($sql);
        $total = $query->row['total'];

        $this->cache->set('product.total.products.' . $cache, $total);

    endif;

    return $total;
}
公共函数getTotalProducts($data=array()){ 如果($this->customer->isloged()): $customer\u group\u id=$this->customer->getCustomerGroupId(); 其他: $customer\u group\u id=$this->config->get('config\u customer\u group\u id'); endif; $sql=“选择计数(不同的p.product\U id)作为总计”; 如果(!empty($data['filter\u category\u id']): 如果(!empty($data['filter\u sub\u category']): $sql.=“来自{$this->prefix}类别\u路径cp 左连接{$this->prefix}产品到类别p2c ON(cp.category_id=p2c.category_id)”; 其他: $sql.=“从{$this->prefix}产品到{u类别p2c”; endif; 如果(!empty($data['filter\u filter']): $sql.=“左连接{$this->prefix}产品过滤器” ON(p2c.product\U id=pf.product\U id) 左连接{$this->prefix}产品p ON(pf.product_id=p.product_id)”; 其他: $sql.=“左连接{$this->prefix}产品p ON(p2c.product_id=p.product_id)”; endif; 其他: $sql.=“来自{$this->prefix}product p”; endif; $sql.=“左连接{$this->prefix}产品描述” ON(p.product\U id=pd.product\U id) 左连接{$this->prefix}product_到_存储p2s ON(p.product\U id=p2s.product\U id) 其中pd.language\u id='”(int)$this->config->get('config\u language\u id')。“' p.status='1'
p.date_available这确实应该进入模型,而不是控制器

我有一个站点有15000多个活动产品。我的方法如下:

public function getTotalProducts($data = array()) {
    if ($this->customer->isLogged()):
        $customer_group_id = $this->customer->getCustomerGroupId();
    else:
        $customer_group_id = $this->config->get('config_customer_group_id');
    endif;  

    $sql = "SELECT COUNT(DISTINCT p.product_id) AS total"; 

    if (!empty($data['filter_category_id'])):
        if (!empty($data['filter_sub_category'])):
            $sql .= " FROM {$this->prefix}category_path cp 
                      LEFT JOIN {$this->prefix}product_to_category p2c 
                        ON (cp.category_id = p2c.category_id)";         
        else:
            $sql .= " FROM {$this->prefix}product_to_category p2c";
        endif;

        if (!empty($data['filter_filter'])):
            $sql .= " LEFT JOIN {$this->prefix}product_filter pf 
                        ON (p2c.product_id = pf.product_id) 
                      LEFT JOIN {$this->prefix}product p 
                        ON (pf.product_id = p.product_id)";
        else:
            $sql .= " LEFT JOIN {$this->prefix}product p 
                        ON (p2c.product_id = p.product_id)";
        endif;
    else:
        $sql .= " FROM {$this->prefix}product p";
    endif;

    $sql .= " LEFT JOIN {$this->prefix}product_description pd 
                ON (p.product_id = pd.product_id) 
              LEFT JOIN {$this->prefix}product_to_store p2s 
                ON (p.product_id = p2s.product_id) 
              WHERE pd.language_id = '" . (int)$this->config->get('config_language_id') . "' 
              AND p.status = '1' 
              AND p.date_available <= NOW() 
              AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'";

    if (!empty($data['filter_category_id'])):
        if (!empty($data['filter_sub_category'])):
            $sql .= " AND cp.path_id = '" . (int)$data['filter_category_id'] . "'"; 
        else:
            $sql .= " AND p2c.category_id = '" . (int)$data['filter_category_id'] . "'";            
        endif;  

        if (!empty($data['filter_filter'])):
            $implode = array();

            $filters = explode(',', $data['filter_filter']);

            foreach ($filters as $filter_id):
                $implode[] = (int)$filter_id;
            endforeach;

            $sql .= " AND pf.filter_id IN (" . implode(',', $implode) . ")";                
        endif;
    endif;

    if (!empty($data['filter_name']) || !empty($data['filter_tag'])):
        $sql .= " AND (";

        if (!empty($data['filter_name'])):
            $implode = array();

            $words = explode(' ', trim(preg_replace('/\s\s+/', ' ', $data['filter_name'])));

            foreach ($words as $word):
                $implode[] = "pd.name LIKE '%" . $this->db->escape($word) . "%'";
            endforeach;

            if ($implode):
                $sql .= " " . implode(" AND ", $implode) . "";
            endif;

            if (!empty($data['filter_description'])):
                $sql .= " OR pd.description LIKE '%" . $this->db->escape($data['filter_name']) . "%'";
            endif;
        endif;

        if (!empty($data['filter_name']) && !empty($data['filter_tag'])):
            $sql .= " OR ";
        endif;

        if (!empty($data['filter_tag'])):
            $sql .= "pd.tag LIKE '%" . $this->db->escape(utf8_strtolower($data['filter_tag'])) . "%'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.model) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.sku) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.upc) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.ean) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.jan) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.isbn) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.mpn) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        $sql .= ")";                
    endif;

    if (!empty($data['filter_manufacturer_id'])):
        $sql .= " AND p.manufacturer_id = '" . (int)$data['filter_manufacturer_id'] . "'";
    endif;

    $cache = md5 ((int)$customer_group_id . serialize ($data));

    $total = $this->cache->get('product.total.products.' . $cache);

    if (!$total):

        $query = $this->db->query($sql);
        $total = $query->row['total'];

        $this->cache->set('product.total.products.' . $cache, $total);

    endif;

    return $total;
}
公共函数getTotalProducts($data=array()){ 如果($this->customer->isloged()): $customer\u group\u id=$this->customer->getCustomerGroupId(); 其他: $customer\u group\u id=$this->config->get('config\u customer\u group\u id'); endif; $sql=“选择计数(不同的p.product\U id)作为总计”; 如果(!empty($data['filter\u category\u id']): 如果(!empty($data['filter\u sub\u category']): $sql.=“来自{$this->prefix}类别\u路径cp 左连接{$this->prefix}产品到类别p2c ON(cp.category_id=p2c.category_id)”; 其他: $sql.=“从{$this->prefix}产品到{u类别p2c”; endif; 如果(!empty($data['filter\u filter']): $sql.=“左连接{$this->prefix}产品过滤器” ON(p2c.product\U id=pf.product\U id) 左连接{$this->prefix}产品p ON(pf.product_id=p.product_id)”; 其他: $sql.=“左联接{$this-
public function getTotalProducts($data = array()) {
    if ($this->customer->isLogged()):
        $customer_group_id = $this->customer->getCustomerGroupId();
    else:
        $customer_group_id = $this->config->get('config_customer_group_id');
    endif;  

    $sql = "SELECT COUNT(DISTINCT p.product_id) AS total"; 

    if (!empty($data['filter_category_id'])):
        if (!empty($data['filter_sub_category'])):
            $sql .= " FROM {$this->prefix}category_path cp 
                      LEFT JOIN {$this->prefix}product_to_category p2c 
                        ON (cp.category_id = p2c.category_id)";         
        else:
            $sql .= " FROM {$this->prefix}product_to_category p2c";
        endif;

        if (!empty($data['filter_filter'])):
            $sql .= " LEFT JOIN {$this->prefix}product_filter pf 
                        ON (p2c.product_id = pf.product_id) 
                      LEFT JOIN {$this->prefix}product p 
                        ON (pf.product_id = p.product_id)";
        else:
            $sql .= " LEFT JOIN {$this->prefix}product p 
                        ON (p2c.product_id = p.product_id)";
        endif;
    else:
        $sql .= " FROM {$this->prefix}product p";
    endif;

    $sql .= " LEFT JOIN {$this->prefix}product_description pd 
                ON (p.product_id = pd.product_id) 
              LEFT JOIN {$this->prefix}product_to_store p2s 
                ON (p.product_id = p2s.product_id) 
              WHERE pd.language_id = '" . (int)$this->config->get('config_language_id') . "' 
              AND p.status = '1' 
              AND p.date_available <= NOW() 
              AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'";

    if (!empty($data['filter_category_id'])):
        if (!empty($data['filter_sub_category'])):
            $sql .= " AND cp.path_id = '" . (int)$data['filter_category_id'] . "'"; 
        else:
            $sql .= " AND p2c.category_id = '" . (int)$data['filter_category_id'] . "'";            
        endif;  

        if (!empty($data['filter_filter'])):
            $implode = array();

            $filters = explode(',', $data['filter_filter']);

            foreach ($filters as $filter_id):
                $implode[] = (int)$filter_id;
            endforeach;

            $sql .= " AND pf.filter_id IN (" . implode(',', $implode) . ")";                
        endif;
    endif;

    if (!empty($data['filter_name']) || !empty($data['filter_tag'])):
        $sql .= " AND (";

        if (!empty($data['filter_name'])):
            $implode = array();

            $words = explode(' ', trim(preg_replace('/\s\s+/', ' ', $data['filter_name'])));

            foreach ($words as $word):
                $implode[] = "pd.name LIKE '%" . $this->db->escape($word) . "%'";
            endforeach;

            if ($implode):
                $sql .= " " . implode(" AND ", $implode) . "";
            endif;

            if (!empty($data['filter_description'])):
                $sql .= " OR pd.description LIKE '%" . $this->db->escape($data['filter_name']) . "%'";
            endif;
        endif;

        if (!empty($data['filter_name']) && !empty($data['filter_tag'])):
            $sql .= " OR ";
        endif;

        if (!empty($data['filter_tag'])):
            $sql .= "pd.tag LIKE '%" . $this->db->escape(utf8_strtolower($data['filter_tag'])) . "%'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.model) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.sku) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.upc) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.ean) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.jan) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.isbn) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        if (!empty($data['filter_name'])):
            $sql .= " OR LCASE(p.mpn) = '" . $this->db->escape(utf8_strtolower($data['filter_name'])) . "'";
        endif;

        $sql .= ")";                
    endif;

    if (!empty($data['filter_manufacturer_id'])):
        $sql .= " AND p.manufacturer_id = '" . (int)$data['filter_manufacturer_id'] . "'";
    endif;

    $cache = md5 ((int)$customer_group_id . serialize ($data));

    $total = $this->cache->get('product.total.products.' . $cache);

    if (!$total):

        $query = $this->db->query($sql);
        $total = $query->row['total'];

        $this->cache->set('product.total.products.' . $cache, $total);

    endif;

    return $total;
}