是什么让此产品搜索MySQL查询变慢?

问题描述 投票:0回答:1

我们正在使用在MySQL 5.7.27和PHP 7.2上运行的OpenCart电子商务平台,其中包含大约5000种产品。

我们使用扩展程序在管理面板中搜索产品,平均执行搜索查询大约需要70-80秒。

原始查询:

SELECT
   SQL_CALC_FOUND_ROWS pd.*,
   p.*,
   (
      SELECT
         price 
      FROM
         product_special 
      WHERE
         product_id = p.product_id 
         AND 
         (
            date_start = '0000-00-00' 
            OR date_start < NOW() 
            AND 
            (
               date_end = '0000-00-00' 
               OR date_end > NOW()
            )
         )
      ORDER BY
         priority,
         price LIMIT 1
   )
   AS special_price,
   IF(p.image IS NOT NULL 
   AND p.image <> '' 
   AND p.image <> 'no_image.png', 'Igen', 'Nem') AS image_text,
   IF(p.status, 'Engedélyezett', 'Letiltott') AS status_text,
   GROUP_CONCAT(DISTINCT CONCAT_WS(' > ', fgd.name, fd.name) 
ORDER BY
   CONCAT_WS(' > ', fgd.name, fd.name) ASC SEPARATOR '
 ') AS filter_text, GROUP_CONCAT(DISTINCT fd.filter_id ORDER BY CONCAT_WS(' > ', fgd.name, fd.name) ASC SEPARATOR '_') AS filter, GROUP_CONCAT(DISTINCT cat.name ORDER BY cat.name ASC SEPARATOR ' ') AS category_text, GROUP_CONCAT(DISTINCT cat.category_id ORDER BY cat.name ASC SEPARATOR '_') AS category, GROUP_CONCAT(DISTINCT IF(p2s.store_id = 0, 'Butopêa HU', s.name) SEPARATOR ' ') AS store_text, GROUP_CONCAT(DISTINCT p2s.store_id SEPARATOR '_') AS store FROM product p LEFT JOIN product_description pd ON (p.product_id = pd.product_id AND pd.language_id = '2') LEFT JOIN product_to_category p2c ON (p.product_id = p2c.product_id) LEFT JOIN (SELECT cp.category_id AS category_id, GROUP_CONCAT(cd1.name ORDER BY cp.level SEPARATOR ' > ') AS name FROM category_path cp LEFT JOIN category c ON (cp.path_id = c.category_id) LEFT JOIN category_description cd1 ON (c.category_id = cd1.category_id) LEFT JOIN category_description cd2 ON (cp.category_id = cd2.category_id) WHERE cd1.language_id = '2' AND cd2.language_id = '2' GROUP BY cp.category_id ORDER BY name) AS cat ON (p2c.category_id = cat.category_id) LEFT JOIN product_to_category p2c2 ON (p.product_id = p2c2.product_id) LEFT JOIN product_filter p2f ON (p.product_id = p2f.product_id) LEFT JOIN filter f ON (f.filter_id = p2f.filter_id) LEFT JOIN filter_description fd ON (fd.filter_id = p2f.filter_id AND fd.language_id = '2') LEFT JOIN filter_group_description fgd ON (f.filter_group_id = fgd.filter_group_id AND fgd.language_id = '2') 
   LEFT JOIN
      product_filter p2f2 
      ON (p.product_id = p2f2.product_id) 
   LEFT JOIN
      product_to_store p2s 
      ON (p.product_id = p2s.product_id) 
   LEFT JOIN
      store s 
      ON (s.store_id = p2s.store_id) 
   LEFT JOIN
      product_to_store p2s2 
      ON (p.product_id = p2s2.product_id) 
GROUP BY
   p.product_id 
ORDER BY
   pd.name ASC LIMIT 0,
   190

我尝试使用MySQL的EXPLAIN功能来查看发生了什么,但是没有任何东西立刻引起我的注意:enter image description here

我的测试环境正在Intel NVME,2666 MHz DDR4 RAM和i7 8th gen上运行。 CPU,但仍然很慢。

我很感谢有关此查询速度降低的任何提示。

mysql optimization opencart
1个回答
0
投票
SELECT中使用了[[看起来有些

许多映射]。 WooCommerce(和底层的Wordpress)的实现方式效率低下。

[这是我有关如何更改架构以提高wp_postmeta和类似表(product_to_category和product_to_store)的性能的讨论:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#speeding_up_wp_postmeta

这可能是

bug

( date_start = '0000-00-00' OR date_start < NOW() AND ( date_end = '0000-00-00' OR date_end > NOW() ) )
您可能想要额外的括号:

( ( date_start = '0000-00-00' OR date_start < NOW() ) AND ( date_end = '0000-00-00' OR date_end > NOW() ) )

也,

( date_start = '0000-00-00' OR date_start < NOW() )

可以

简化

到] ( date_start < NOW() )
并且,查询似乎具有

explode-implode症候群

,其中JOINs展开以生成一个大的临时表,而仅使GROUP BY折叠至原始大小。解决方法是转向 GROUP_CONCAT(... foo.x ...) AS blah. ... LEFT JOIN foo ... ON ...
进入

( SELECT GROUP_CONCAT(... foo.x ...) FROM foo WHERE ... ) AS blah,

如果消除了所有的LEFT JOINs,那么也可以消除GROUP BY  p.product_id

不说

LEFT JOIN

,如果'right'表不是可选的。 (相反,说JOIN。) LEFT JOIN category_description cd1 ON (cp.category_id = cd1.category_id) WHERE cd1.language_id = '2' -- this invalidates the `LEFT` 似乎不使用

cd2

,除了检查cd2.language_id = '2'。考虑删除对其的引用。这需要

两个临时表

,因为它们是不同的: GROUP BY p.product_id ORDER BY pd.name ASC
[我是不是说pd.name只是'语言'2中p.product_id的名称?如果是这样,这在语义上可能是相同的,但是由于消除了临时表和排序,所以速度更快):

GROUP BY pd.name ORDER BY pd.name

完成后,最好将INDEX(language_id, name)放在pd上。

LIMIT 0, 190中的speedup

通常被SQL_CALC_FOUND_ROWS消除。

过度规范化

导致这两个组成部分在单独的表中?

CONCAT_WS(' > ', fgd.name, fd.name)

© www.soinside.com 2019 - 2024. All rights reserved.