1

我以前不知道,但是 Opencart 官方版本中有一个巨大的错误,在一个商店里,当你有很多产品和类别时,它需要 50 秒!!!加载页面。50秒!!!,我查看了代码和谷歌,发现问题有据可查,因为几乎每个人都知道这条线导致了一切。(从缓存中计算)

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

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

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

                $product_total = "";

无论如何,我的问题已经解决了(页面加载在 3 秒内而不是 50 秒内),但是计数丢失了所以我一直在寻找,最后我发现这个解决方案非常好,(直到现在,仍在测试)如果你的数据库是最好的解决方案正在处理很多产品和类别.. http://ergopho.be/speeding-up-opencart-using-the-cache-class/

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

在 Controller/Common/Header.php 您还可以找到此代码(在他在类别上执行的文章中)这里也是此文件中的代码

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

$categories = $this->model_catalog_category->getCategories(0);



        foreach ($categories as $category) {

            if ($category['top']) {

                // Level 2

                $children_data = array();



                $children = $this->model_catalog_category->getCategories($category['category_id']);



                foreach ($children as $child) {

                    $data = array(

                        'filter_category_id'  => $child['category_id'],

                        'filter_sub_category' => true

                    );



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


                    $children_data[] = array(

                        'name'  => $child['name'] . ($this->config->get('config_product_count') ? ' (' . $product_total . ')' : ''),

                        'href'  => $this->url->link('product/category', 'path=' . $category['category_id'] . '_' . $child['category_id'])

                    );                      

                }


Yo have to wrap all this code into this lines

$this->data['categories'] = $this->cache->get('categories');
if(!count($this->data['categories'])) { 

<!--Here goes the above code-->

$this->cache->set('categories', $this->data['categories']);
}

到目前为止它工作正常,我希望这对其他人有帮助,还请注意,如果你有更好的方法,我知道有很多非高级用户正在寻找这个,所以如果你可以与我们分享, 那会很好。

¿ 任何人都可以为这个可怕的缓慢错误找到更好的解决方案吗?

谢谢,免得希望 Opencart 的下一个版本可以解决此类问题。

希望这可以帮助。和平

4

1 回答 1

1

这确实应该进入模型而不是控制器。

我有一个拥有超过 15,000 种有效产品的网站。我的方法是这样的:

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

您会注意到靠近末尾的缓存部分。

我还转换为 memcached 用于缓存查询结果,而不是文件缓存。当您将 seo_urls 用于这么多产品时,真正的问题出现了,我必须完全重写整个 SeoUrl 控制器和 Url 库,但它很快而且我有很棒的 url :)

于 2013-09-04T11:57:47.940 回答