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